Spring @Value 配置项解析 vs Spring @ConfigurationProperties 配置项解析

@ConfigurationProperties 的属性注入是在 initializeBean() 的时候处理的,即 populateBean() 之后,由 ConfigurationPropertiesBindingPostProcessor 处理的,最终会委托给 Environment 来处理(参看:SpringBoot 配置项解析)。
@Value 的属性注入是在 populateBean() 的时候处理的,是当作依赖进行注入的。最后是通过 AbstractBeanFactory.embeddedValueResolvers (一组 StringValueResoulver 的集合)  解析的,它非常强大,支持 占位符 ${} spEL(#{})

org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue()

public String resolveEmbeddedValue(@Nullable String value) {
    if (value == null) {
        return null;
    }
    String result = value;
    for (StringValueResolver resolver : this.embeddedValueResolvers) {
        result = resolver.resolveStringValue(result);
        if (result == null) {
            return null;
        }
    }
    return result;
}

StringValueResolver、EmbeddedValueResolver
EmbeddedValueResolver implements StringValueResolver。EmbeddedValueResolver 非常强大,它是 spring 配置解析的核心。先解析占位符 ${},再解析 spEL(#{})

 1 public class EmbeddedValueResolver implements StringValueResolver {
 2     private final BeanExpressionContext exprContext;
 3     private final BeanExpressionResolver exprResolver;
 4 
 5     public EmbeddedValueResolver(ConfigurableBeanFactory beanFactory) {
 6         this.exprContext = new BeanExpressionContext(beanFactory, null);
 7         this.exprResolver = beanFactory.getBeanExpressionResolver(); // 实现类为:StandardBeanExpressionResolver
 8     }
 9 
10     @Override
11     public String resolveStringValue(String strVal) {
12         // 1. 解析占位符${}
13         String value = this.exprContext.getBeanFactory().resolveEmbeddedValue(strVal);
14         if (this.exprResolver != null && value != null) {
15             // 2. 解析 spEL: #{}
16             Object evaluated = this.exprResolver.evaluate(value, this.exprContext);
17             value = (evaluated != null ? evaluated.toString() : null);
18         }
19         return value;
20     }
21 
22 }

配置写法小技巧:
可以使用嵌套写法 和 默认值。举例:
${server.error.path:${error.path:/error}}

问题思考:
用了 disconf 之后,在使用 SpringBoot @ConfigurationProperties 形式的配置时,是不是就不用写 @PropertySource("classpath:redis.properties") 来指定配置文件了?因为 diconf 已经将托管的 property 配置文件纳入 spring 管理了,如果这样该多方便啊。那确实可以这么干吗?
(在使用 disconf 托管配置文件时,会配置 org.springframework.context.support.PropertySourcesPlaceholderConfigurer 或者 com.baidu.disconf.client.addons.properties.ReloadingPropertyPlaceholderConfigurer,被托管的配置都会纳入 spring 管理。)

分析:
通过测试发现是不可以的,因为 @ConfigurationProperties 最终委托给 Environment 来处理,而 PropertySourcesPlaceholderConfigurer 和 ReloadingPropertyPlaceholderConfigurer 都不受 Environment 控制,所以是不支持的。
而 @Value 却是可以注入 disconf 托管的配置的,因为 @Value 注入的配置会通过 StringValueResoulver 来解析,而 PropertySourcesPlaceholderConfigurer 和 ReloadingPropertyPlaceholderConfigurer 管理的配置,最终会间接通过 StringValueResolver 来解析

资料:
https://blog.csdn.net/f641385712/article/details/91380598

原文地址:https://www.cnblogs.com/kevin-yuan/p/12213644.html