分布式配置中心的多 JGit 仓库是如何匹配与实现?
《配置中心 Spring Cloud Config 详解》系列文章更新,一起在技术的路上精进!本系列文章将会介绍Spring Cloud 中提供了分布式配置中心Spring Cloud Config。应用服务中除了实现系统功能的代码,还需要连接资源和其它应用,经常有很多需要在外部配置的数据去调整应用的行为,如切换不同的数据库,设置功能开关等。随着微服务的不断增加,需要系统具备可伸缩和可扩展性,除此之外就是管理相当多的服务实例的配置数据。在应用的开发阶段由各个服务自治,但是到了生产环境之后会给运维带来很大的麻烦,特别是微服务的规模比较大,配置的更新更为麻烦。为此,系统需要建立一个统一的配置管理中心。
在前面的文章,我们介绍了 JGit 获取最新的远端仓库配置以及多 JGit 仓库实现。本文将会进一步介绍多个 repos 的匹配规则,这也是多 JGit 仓库实现的一个关键步骤。
多个 repos 的匹配规则
前面已经说过,MultipleJGitEnvironmentRepository
是环境仓库的默认实现方式,继承自JGitEnvironmentRepository
,支持Git地址的占位符,模式匹配以及多个仓库的配置。上面截取的代码中,定义了repos变量,该表量是一个Map类型,key对应每一个repo名字,value则是静态内部类PatternMatchingJGitEnvironmentRepository
。下面我们具体看一下,多个repo规则是在源码中的实现。
public static class PatternMatchingJGitEnvironmentRepository
extends JGitEnvironmentRepository {
private String[] pattern = new String[0]; // 1
private String name; // 2
...
public boolean matches(String application, String profile, String label) { // 3
...
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
for (int i = profiles.length; i-- > 0;) {
if (PatternMatchUtils.simpleMatch(this.pattern,
application + "/" + profiles[i])) { // 4
return true;
}
}
return false;
}
public void setPattern(String[] pattern) { // 5
Collection<String> patterns = new ArrayList<>();
List<String> otherProfiles = new ArrayList<>();
for (String p : pattern) {
if (p != null) {
if (!p.contains("/")) { // 6
patterns.add(p + "/*");
}
if (!p.endsWith("*")) { // 7
otherProfiles.add(p + ",*");
}
}
patterns.add(p);
}
patterns.addAll(otherProfiles);
...
this.pattern = patterns.toArray(new String[0]);
}
}
}
- 匹配application和profiles的模式串数组;
- 仓库名,默认为map的key值;
- 匹配application、profile与模式串是否匹配;
- 匹配给定模式的字符串;
- pattern的setter方法,用来补全一些缺省书写格式;
- 缺少profile的情况, 将会补齐"/ * ",匹配任意的profile;
- 不以 * 结尾的情况,即指定了profile,默认规则会补齐", * "。
通过模式匹配{application}/{profile}
,可以实现更复杂的需求,pattern可以使用通配符支持列表的形式。在PatternMatchingJGitEnvironmentRepository
中,由于继承自JGitEnvironmentRepository
,所以模式匹配这种模式实现了获取应用服务配置信息等方法。
在PatternMatchingJGitEnvironmentRepository
对patterns进行了预处理,在pattern的setter方法中补全一些配置缺省书写格式,如上面提到的缺省profile的情况。matches
方法匹配application、profile与模式串是否匹配,这边主要调用的是Spring的工具类方法进行判断。#simpleMatch
是Spring util中的工具类PatternMatchUtils
提供的方法,用于处理目标字符串与模式串是否匹配。
public static boolean simpleMatch(String pattern, String str) {
if (pattern == null || str == null) {
return false;
}
int firstIndex = pattern.indexOf('*');
if (firstIndex == -1) { // 1
return pattern.equals(str);
}
if (firstIndex == 0) { // 2
if (pattern.length() == 1) {
return true;
}
int nextIndex = pattern.indexOf('*', firstIndex + 1);
if (nextIndex == -1) { // 3
return str.endsWith(pattern.substring(1));
}
String part = pattern.substring(1, nextIndex); // 4
if ("".equals(part)) { //5
return simpleMatch(pattern.substring(nextIndex), str);
int partIndex = str.indexOf(part); // 6
while (partIndex != -1) { // 7
if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) {
return true;
}
partIndex = str.indexOf(part, partIndex + 1);
}
return false;
}
return (str.length() >= firstIndex &&
pattern.substring(0, firstIndex).equals(str.substring(0, firstIndex)) &&
simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex))); // 8
}
- 如果没有通配符,严格匹配
- 处理以 * 开头的情况
- 如果只有一个 * ,后半部分严格匹配
- 截断第一个 * 与第二个*之间的字符串
- 处理后半部分为空的情况
- 目标串索引到该part
- 索引到的情况,递归验证后续字符串,否则失败
- 最后将前半部分进行严格匹配,后半部分进行递归调用
利用Spring的工具类方法进行判断,匹配给定模式的字符串,支持以下简单模式样式:“xxx ”,“ xxx”,“* xxx *”和“xxx * yyy”(具有任意数量的模式部分),以及完全相等的匹配模式。
小结
本文主要介绍了 Spring Cloud Config 服务端 Config Server 中多个 repos 的匹配规则的实现。在有些场景下,我们可能需要从多个环境仓库中拉取配置数据。通过在 config server 中的 application.properties 或 application.yml 激活多个 profile,比如同时从 Git 和 SVN 仓库拉取配置数据,下面的文章将会重点介绍如何通过组合方式获取环境配置。
- 点赞
- 收藏
- 关注作者
评论(0)