Bart Boersma
Bart Boersma

Reputation: 274

Why does @Value as parameter of constructor fill the property correctly?

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().

Spring Bean life cycle

How come this is still working?

Regards,

Bart

Upvotes: 5

Views: 792

Answers (1)

Dmitrii Cheremisin
Dmitrii Cheremisin

Reputation: 1568

This behavior is supported by PropertySourcesPlaceholderConfigurer

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

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.

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

  1. Bean Factory Post Processors update bean definitions. Example, PropertySourcesPlaceholderConfigurer.

  2. 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

Related Questions