Reputation: 274
My question is: Why does this piece of code correctly set the constructor parameter property port
:
private final RedisServer redisServer;
public RedisTestConfiguration(@Value("${cache.port}") final int port) {
this.redisServer = new RedisServer(port);
}
As of my understanding, @Value("${cache.port}")
is resolved by a BeanPostProcessor called AutowiredAnnotationBeanPostProcessor. Spring bean lifecycle works in a way that the constructor method is called before any BeanPostProcess, see picture below. Note The constructor is called before BeanPostProcessor.postProcessBeforeInitialization().
How come this is still working?
Regards,
Bart
Upvotes: 5
Views: 792
Reputation: 1568
This behavior is supported by PropertySourcesPlaceholderConfigurer
PropertySourcesPlaceholderConfigurer is a BeanFactoryPostProcessor. It collects @Value fields and updates bean definition in spring container. PropertySourcesPlaceholderConfigurer should be created in the container before any bean is initialized.
Bean metadata is described here in the documentation: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-metadata
So, the flow is the following: 1. Bean definition readers collect beans declarations in xml files or from java classes. Example, XmlBeanDefinitionReader.
Bean Factory Post Processors update bean definitions. Example, PropertySourcesPlaceholderConfigurer.
Spring container looks at the bean definition and creates beans(calls constructor) according to bean definition values. Ref: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-class
So, the problem is that
As of my understanding, @Value("${cache.port}") is resolved by a BeanPostProcessor
is not correct. @Value is managed by BeanFactoryPostProcessor, not BeanPostProcessor
Actually, documentation states:
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 has some kind of default property resolver, that is another BeanFactoryPostProcessor. But it is possible to override it with PropertySourcesPlaceholderConfigurer
Upvotes: 3