SpringBoot 配置项解析 && @PropertySource 注解的处理

SpringBoot 的配置解析是通过 Environment 来实现的。

Environment:
与属性相关的 Environment 对象的作用是为用户提供一个方便的服务接口,用于配置属性源并从中解析属性。

Environment 本身实现了 PropertyResolver 接口,最终会委托给 PropertySourcesPropertyResolver 去解析配置。

org.springframework.core.env.PropertySourcesPropertyResolver.getProperty

 1 protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
 2     if (this.propertySources != null) {
 3         for (PropertySource<?> propertySource : this.propertySources) { // 1. 循环 PropertySources
 4             if (logger.isTraceEnabled()) {
 5                 logger.trace("Searching for key '" + key + "' in PropertySource '" +
 6                         propertySource.getName() + "'");
 7             }
 8             Object value = propertySource.getProperty(key); // 2. 从 PropertySource 中获取 key 对应的配置
 9             if (value != null) {
10                 if (resolveNestedPlaceholders && value instanceof String) {
11                     value = resolveNestedPlaceholders((String) value); // 3. 解析占位符 ${}
12                 }
13                 logKeyFound(key, propertySource, value);
14                 return convertValueIfNecessary(value, targetValueType); // 4. 转换成指定类型
15             }
16         }
17     }
18     if (logger.isTraceEnabled()) {
19         logger.trace("Could not find key '" + key + "' in any property source");
20     }
21     return null;
22 }

 

 

 最终获取配置就是去各种 PropertySource 中去取 key 对应的配置值,SpringBoot 支持多种类型的 PropertySource 扩展:

RandomValuePropertySource -- 对 random.int, random.long, random.uuid 的支持
MapPropertySource -- 对 K,V 形式的配置支持
JsonPropertySource -- 对 Json 类型的配置支持
SystemEnvironmentPropertySource -- 对配置 key 中使用 .、下划线、中划线、大小写的支持
CommandLinePropertySource -- 对启动命令参数的支持
ServletContextPropertySource -- 对 ServletContext 的 initParam 的支持
JndiPropertySource -- 对 JNDI 类型的配置支持

 

@PropertySource 注解的处理

ConfigurationClassParser#doProcessConfigurationClass()
在处理 @PropertySource 时,会加载注解中定义的资源文件,然后添加到 Environment#propertySources 中。
添加时,如果指定了多个资源文件,则后面定义的会放到 propertySources 的前面。这个会影响配置优先级,即后定义的优先级高

// 对所有的 @PropertySource 而言的
// 单个 @PropertySource 中定义多个资源文件地址也受这个规则影响
if (this.propertySourceNames.isEmpty()) {
    propertySources.addLast(propertySource);
} else {
    String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
    propertySources.addBefore(firstProcessed, propertySource);
}

 注意:
这个规则是对所有的 @PropertySource 注解生效的,因为 ConfigurationClassParser 只有一个实例,所以 propertySourceNames 变量也是共用一个,所以它会对所有的 @PropertiesSource 注解生效。
从表现上来看就是:
1. 从全局来看,后加载的 @PropertySource 资源文件优先级会排在前面
2. 从局部来看,@PropertySource 中指定多个资源文件时,后定义的资源文件优先级更高

 

posted on 2020-01-02 13:58  快鸟  阅读(1506)  评论(0编辑  收藏  举报