为什么@Value 作为构造函数的参数正确填充属性?

Bar*_*sma 5 java spring spring-boot

我的问题是:为什么这段代码正确设置了构造函数参数属性port

private final RedisServer redisServer;

public RedisTestConfiguration(@Value("${cache.port}") final int port) {
   this.redisServer = new RedisServer(port);
}
Run Code Online (Sandbox Code Playgroud)

据我了解,@Value("${cache.port}")是由名为 AutowiredAnnotationBeanPostProcessor 的 BeanPostProcessor 解决的。Spring bean 生命周期的工作方式是在任何 BeanPostProcess 之前调用构造函数方法,请参见下图。注意构造函数在 BeanPostProcessor.postProcessBeforeInitialization() 之前被调用。

Spring Bean 生命周期

这怎么还在工作?

问候,

巴特

小智 3

PropertySourcesPlaceholderConfigurer 支持此行为

参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-placeholderconfigurer

PropertySourcesPlaceholderConfigurer 是一个 BeanFactoryPostProcessor。它收集 @Value 字段并更新 spring 容器中的 bean 定义。PropertySourcesPlaceholderConfigurer 应在初始化任何 bean 之前在容器中创建。

文档中描述了 Bean 元数据: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-metadata

因此,流程如下: 1. Bean 定义读取器在 xml 文件或 java 类中收集 Bean 声明。例如,XmlBeanDefinitionReader。

参考: https: //docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.html

  1. Bean Factory 后处理器更新 Bean 定义。例如,PropertySourcesPlaceholderConfigurer。

  2. Spring容器查看bean定义并根据bean定义值创建bean(调用构造函数)。参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-class

所以,问题是这 As of my understanding, @Value("${cache.port}") is resolved by a BeanPostProcessor是不正确的。@Value是由BeanFactoryPostProcessor管理的,而不是BeanPostProcessor

实际上,文档指出:

A default lenient embedded value resolver is provided by Spring. It will try to resolve the property value and if it cannot be resolved, the property name (for example ${catalog.name}) will be injected as the value. If you want to maintain strict control over nonexistent values, you should declare a PropertySourcesPlaceholderConfigurer bean, as the following example shows:...

Spring有某种默认的属性解析器,那就是另一个BeanFactoryPostProcessor。但可以使用 PropertySourcesPlaceholderConfigurer 覆盖它