springcloud config配置读取优先级过程详解

网友投稿 378 2022-12-26


springcloud config配置读取优先级过程详解

情景描述

最近在修复Eureka的静态页面加载不出的缺陷时,最终发现是远程GIT仓库将静态资源访问方式配置给禁用了(spring.resources.add-mappings=false)。虽然最后直接修改远程GIT仓库的此配置项给解决了(spring.resources.add-mappings=true),但是从中牵涉出的配置读取优先级我们必须好好的再回顾下

springcloud config读取仓库配置

通过config client模块来读取远程的仓库配置,只需要在boostrap.properties文件中配置如下属性即可

spring.application.name=eureka

spring.cloud.config.uri=http://localhost:8888

spring.cloud.config.name=dev

spring.cloud.config.username=dev

spring.cloud.config.password=dev

其就会以GET方式去请求http://localhost:8888/eureka/dev地址从而将配置拉取下来。

当然上述的API地址也是需要被访问服务器部署了config server服务方可调用,具体的细节就不展开了

外部源读取优先级

我们都知道spring的配置属性管理均是存放在Enviroment对象中,就以普通项目StandardEnvironment为例,其配置的存放顺序可罗列如下

顺位

key

来源

说明

1

commandLineArgs

传入main函数的参数列表

Program arguments

2

systemProperties

System.getProperties()

JDK属性列表、操作系统属性、-D开头的VM属性等

3

systemEnvironment

System.getEnv()

环境属性,例如java_HOME/M2_HOME

4

${file_name}

配置文件

例如application.yml

5

defaultProperties

SpringApplicationBuilder#properties()

那么远程读取的配置的存放应该放在上述的哪个位置呢?

我们都知道boostrap上下文通过暴露org.springframework.cloud.bootstrap.config.PropertySourceLocator接口来方便集成第三方的外部源配置读取,比如本文提及的config client模块中的org.springframework.cloud.config.client.ConfigServicePropertySourceLocator实现类。

但最终将外部源配置读取以及插入至Environment对象中则是通过org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration类来完成的。

PropertySourceBootstrapConfiguration

此类也是ApplicationContextInitializer接口的实现类,阅读过cloud源码的都知道,此类被调用是在子类上下JCbcamwxN文初始化的时候,我们主要看下其复写的initialize()方法

@Override

public void initialize(ConfigurableApplicationContext applicationContext) {

CompositePropertySource composite = new CompositePropertySource(

BOOTSTRAP_PROPERTY_SOURCE_NAME);

// 对在boostrap上下文类型为PropertySourceLocator的bean集合进行排序

AnnotationAwareOrderComparator.sort(this.propertySourceLocators);

boolean empty = true;

ConfigurableEnvironment environment = applicationContext.getEnvironment();

for (PropertySourceLocator locator : this.propertySourceLocators) {

PropertySource> source = null;

// 读取外部配置源

source = locator.locate(environment);

if (source == null) {

continue;

}

logger.info("Located property source: " + source);

composite.addPropertySource(source);

empty = false;

}

if (!empty) {

MutablePropertySources propertySources = environment.getPropertySources();

String logConfig = environment.resolvePlaceholders("${logging.config:}");

LogFile logFile = LogFile.get(environment);

if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {

propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);

}

// 插入至Environment环境对象中

insertPropertySources(propertySources, composite);

reinitializeLoggingSystem(environment, logConfig, logFile);

setLogLevels(applicationContext, environment);

handleIncludedProfiles(environment);

}

}

直接观察对应的insertPropertySources()方法

private void insertPropertySources(MutablePropertySources propertySources,

CompositePropertySource composite) {

// 外部源配置集合

MutablePropertySources incoming = new MutablePropertySources();

incoming.addFirst(composite);

PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties();

// 从外部源配置源集合中读取PropertySourceBootstrapProperties的相关属性

// 例如spring.cloud.config.overrideSystemProperties等属性

Binder.get(environment(incoming)).bind("spring.cloud.config",

Bindable.ofInstance(remoteProperties));

// spring.cloud.config.allow-override=false或者spring.cloud.config.override-none=false且spring.cloud.config.override-system-properties=true

if (!remoteProperties.isAllowOverride() || (!remoteProperties.isOverrideNone()

&& remoteProperties.isOverrideSystemProperties())) {

propertySources.addFirst(composite);

return;

}

// spring.cloud.config.override-none=true则处于最低读取位

if (remoteProperties.isOverrideNone()) {

propertySources.addLast(composite);

return;

}

// 根据spring.cloud.config.override-system-properties属性判断是放在systemProperties前还是后

if (propertySources

.contains(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) {

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);

}

}

对上述的代码描述作下总结

1.上述的配置属性均会映射到PropertySourceBootstrapProperties实体类中,且其中的默认值罗列如下

属性

默认值

说明

spring.cloud.config.allow-override

true

外部源配置是否可被覆盖

spring.cloud.config.override-none

false

外部源配置是否不覆盖任何源

spring.cloud.config.override-system-properties

true

外部源配置是否可覆盖本地属性

2.针对相应的属性的值对应的外部源在Environment对象中的读取优先级,罗列如下

属性

读取优先级

spring.cloud.config.allow-override=false

最高

spring.cloud.config.override-none=false&&spring.cloud.config.override-system-properties=true

最高(默认)

spring.cloud.config.override-none=true

最低

spring上下文无systemEnvironment属性

最低

spring上下文有systemEnvironment属性 && spring.cloud.config.override-system-properties=false

在systemEnvironment之后

spring上下文有systemEnvironment属性 && spring.cloud.config.override-system-properties=false

在systemEnvironment之前

即默认情况下,外部源的配置属性的读取优先级是最高的。

且除了spring.cloud.config.override-none=true的情况下,其他情况下外部源的读取优先级均比本地配置文件高。

Note:值得注意的是,如果用户想复写上述的属性,则放在bootstrap.yml|application.yml配置文件中是无效的,根据源码分析只能是自定义一个PropertySourceLocator接口实现类并放置在相应的spring.factories文件中方可生效。

自定义PropertySourceLocator接口

针对上文描述,假设有这么一个场景,远程仓库的配置都是公有的,我们也不能修改它,我们只在项目中去复写相应的配置以达到兼容的目的。那么用户就需要自定义去编写接口了

1.编写PropertySourceLocator接口实现类

package com.example.configdemo.propertysource;

import org.springframework.cloud.bootstrap.config.PropertySourceLocator;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import org.springframework.core.env.Environment;

import org.springframework.core.env.MapPropertySource;

import org.springframework.core.env.PropertySource;

import java.util.HashMap;

import java.util.Map;

/**

* @author nanco

* @create 19/9/22

* @description 自定义的PropertySourceLocator的顺序应该要比远程仓库读取方式要优先

* @see org.springframework.cloud.config.client.ConfigServicePropertySJCbcamwxNourceLocator

*/

@Order(value = Ordered.HIGHEST_PRECEDENCE + 1)

public class CustomPropertySourceLocator implements PropertySourceLocator {

private static final String OVERRIDE_ADD_MAPPING = "spring.resources.add-mappings";

@Override

public PropertySource> locate(Environment environment) {

Map customMap = new HashMap<>(2);

// 远程仓库此配置为false,本地进行复写

customMap.put(OVERRIDE_ADD_MAPPING, "true");

return new MapPropertySource("custom", customMap);

}

}

2.编写BootstrapConfiguration

package com.example.configdemo.propertysource;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

/**

* @author nanco

* @create 19/9/22

*/

@Configuration

public class CustomBootstrapConfiguration {

@Bean("customPropertySourceLocator")

public CustomPropertySourceLocator propertySourceLocator() {

return new CustomPropertySourceLocator();

}

}

3.在src\main\resources目录下创建META-INF\spring.factories文件

# Bootstrap components

org.springframework.cloud.bootstrap.BootstrapConfiguration=\

com.example.configdemo.propertysource.CustomBootstrapConfiguration

4.运行main函数即可

小结

默认情况下,外部源配置拥有最高的优先级。在spring.cloud.config.override-none=false的情况下,外部源配置也比本地文件拥有更高的优先级。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java求余的技巧汇总
下一篇:运行控制系统接口设计方案(操作系统接口设计)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~