Spring Cloud覆写远端配置属性的示例分析

发布时间:2021-07-15 11:22:09 作者:小新
来源:亿速云 阅读:172

这篇文章主要介绍Spring Cloud覆写远端配置属性的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

应用的配置源通常都是远端的Config Server服务器,默认情况下,本地的配置优先级低于远端配置仓库。如果想实现本地应用的系统变量和config文件覆盖远端仓库中的属性值,可以通过如下设置:

spring:
cloud:
config:
allowOverride: true
overrideNone: true
overrideSystemProperties: false

客户端通过如上配置,可以实现本地配置优先级更高,且不能被覆盖。由于我们基于的Spring Cloud当前版本是 Edgware.RELEASE ,上面的设置并不能起作用,而是使用了 PropertySourceBootstrapProperties 中的默认值。具体情况见issue: https://github.com/spring-cloud/spring-cloud-commons/pull/250 ,我们在下面分析时会讲到具体的bug源。

源码分析

ConfigServicePropertySourceLocator

覆写远端的配置属性归根结底与客户端的启动时获取配置有关,在获取到配置之后如何处理?我们看一下spring cloud config中的资源获取类 ConfigServicePropertySourceLocator 的类图。

Spring Cloud覆写远端配置属性的示例分析 

ConfigServicePropertySourceLocator 实质是一个属性资源定位器,其主要方法是 locate(Environment environment) 。首先用当前运行应用的环境的application、profile和label替换configClientProperties中的占位符并初始化RestTemplate,然后遍历labels数组直到获取到有效的配置信息,最后还会根据是否快速失败进行重试。主要流程如下:

Spring Cloud覆写远端配置属性的示例分析 

locate(Environment environment) 调用 getRemoteEnvironment(restTemplate, properties, label, state) 方法通过http的方式获取远程服务器上的配置数据。实现也很简单,显示替换请求路径path中占位符,然后进行头部headers组装,组装好了就可以发送请求,最后返回结果。

在上面的实现中,我们看到获取到的配置信息存放在 CompositePropertySource ,那是如何使用它的呢?这边补充另一个重要的类是PropertySourceBootstrapConfiguration,它实现了ApplicationContextInitializer接口,该接口会在应用上下文刷新之前 refresh() 被回调,从而执行初始化操作,应用启动后的调用栈如下:

SpringApplicationBuilder.run() -> SpringApplication.run() -> SpringApplication.createAndRefreshContext() -> SpringApplication.applyInitializers() -> PropertySourceBootstrapConfiguration.initialize()
PropertySourceBootstrapConfiguration

而上述 ConfigServicePropertySourceLocator 的locate方法会在initialize中被调用,从而保证上下文在刷新之前能够拿到必要的配置信息。具体看一下initialize方法:

public class PropertySourceBootstrapConfigurationimplements
 ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
 private int order = Ordered.HIGHEST_PRECEDENCE + 10;
 @Autowired(required = false)
 private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>();
 @Override
 public void initialize(ConfigurableApplicationContext applicationContext){
 CompositePropertySource composite = new CompositePropertySource(
 BOOTSTRAP_PROPERTY_SOURCE_NAME);
 //对propertySourceLocators数组进行排序,根据默认的AnnotationAwareOrderComparator
 AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
 boolean empty = true;
 //获取运行的环境上下文
 ConfigurableEnvironment environment = applicationContext.getEnvironment();
 for (PropertySourceLocator locator : this.propertySourceLocators) {
 //遍历this.propertySourceLocators
 PropertySource<?> source = null;
 source = locator.locate(environment);
 if (source == null) {
 continue;
 }
 logger.info("Located property source: " + source);
 //将source添加到PropertySource的链表中
 composite.addPropertySource(source);
 empty = false;
 }
 //只有source不为空的情况,才会设置到environment中
 if (!empty) {
 //返回Environment的可变形式,可进行的操作如addFirst、addLast
 MutablePropertySources propertySources = environment.getPropertySources();
 String logConfig = environment.resolvePlaceholders("${logging.config:}");
 LogFile logFile = LogFile.get(environment);
 if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
 //移除bootstrapProperties
 propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
 }
 //根据config server覆写的规则,设置propertySources
 insertPropertySources(propertySources, composite);
 reinitializeLoggingSystem(environment, logConfig, logFile);
 setLogLevels(environment);
 //处理多个active profiles的配置信息
 handleIncludedProfiles(environment);
 }
 }
 //...
}

下面我们看一下,在 initialize 方法中进行了哪些操作。

返回Environment的可变形式,可进行的操作如addFirst、addLast

移除propertySources中的bootstrapProperties

根据config server覆写的规则,设置propertySources

处理多个active profiles的配置信息

初始化方法 initialize 处理时,先将所有PropertySourceLocator类型的对象的 locate 方法遍历,然后将各种方式得到的属性值放到CompositePropertySource中,最后调用 insertPropertySources(propertySources, composite) 方法设置到Environment中。Spring Cloud Context中提供了覆写远端属性的 PropertySourceBootstrapProperties ,利用该配置类进行判断属性源的优先级。

private void insertPropertySources(MutablePropertySources propertySources,
 CompositePropertySource composite) {
 MutablePropertySources incoming = new MutablePropertySources();
 incoming.addFirst(composite);
 PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties();
 new RelaxedDataBinder(remoteProperties, "spring.cloud.config")
 .bind(new PropertySourcesPropertyValues(incoming));
 //如果不允许本地覆写
 if (!remoteProperties.isAllowOverride() || (!remoteProperties.isOverrideNone()
 && remoteProperties.isOverrideSystemProperties())) {
 propertySources.addFirst(composite);
 return;
 }
 //overrideNone为true,外部配置优先级最低
 if (remoteProperties.isOverrideNone()) {
 propertySources.addLast(composite);
 return;
 }
 if (propertySources
 .contains(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) {
 //根据overrideSystemProperties,设置外部配置的优先级
 if (!remoteProperties.isOverrideSystemProperties()) {
 propertySources.addAfter(
  StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
  composite);
 }
 else {
 propertySources.addBefore(
  StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
  composite);
 }
 }
 else {
 propertySources.addLast(composite);
 }
}

上述实现主要是根据 PropertySourceBootstrapProperties 中的属性,调整多个配置源的优先级。从其实现可以看到 PropertySourceBootstrapProperties 对象的是被直接初始化,使用的是默认的属性值而并未注入我们在配置文件中设置的。

修复后的实现:

@Autowired(required = false)
 private PropertySourceBootstrapProperties remotePropertiesForOverriding;
 @Override
 public int getOrder(){
 return this.order;
 private void insertPropertySources(MutablePropertySources propertySources,
 CompositePropertySource composite) {
 MutablePropertySources incoming = new MutablePropertySources();
 incoming.addFirst(composite);
 PropertySourceBootstrapProperties remoteProperties = remotePropertiesForOverriding == null
 ? new PropertySourceBootstrapProperties()
 : remotePropertiesForOverriding;

以上是“Spring Cloud覆写远端配置属性的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. Spring Boot外部化配置实战解析
  2. Spring Cloud Zuul路由规则动态更新的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springcloud

上一篇:Struts2拦截器Interceptor原理与配置的示例分析

下一篇:C#中怎么操作符重载应用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》