2
votes

I'm using Spring Framework 4.3 without Spring Boot. As far as I understand about the bean lifecycle :

  1. load bean definitions
  2. process bean definitions using beanFactoryPostProcessor classes
  3. instanciate and inject beans (loop with the right order)
  4. use beans
  5. let the garbage collector destroy beans

PropertyPlaceholderConfigurer is a BeanFactoryPostProcessor. so @Value properties must be read before instanciating beans. (step 2).

this is my code, Main class :

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    ReadValueFromFile dc = ctx.getBean(ReadValueFromFile.class);
    System.out.println("Main : " + dc.getUrl());
}

ReadValueFromFile.java

@Component
@PropertySource("classpath:db/db.properties")
public class ReadValueFromFile {
    @Value("${url}")
    private String url;

    public ReadValueFromFile() {
        System.out.println("url constructor : " +  url);
    }

    @PostConstruct
    void init() {
        System.out.println("url postconstruct : " +  url);
    }

    @PreDestroy
    void dest() {
        System.out.println("url @PreDestroy : " +  url);
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

Config class :

@Configuration
@ComponentScan(basePackages={"tn.esprit.beans"})
public class AppConfig {

     //it works well without declaring this bean.
//   @Bean
//   public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
//      return new PropertySourcesPlaceholderConfigurer();
//   }
}

and finally my properties file under src/main/resources/db :

url=jdbc:mariadb://localhost:3306/client_project

When I run main class I get this output :

url constructor : null
url postconstruct : jdbc:mariadb://localhost:3306/client_project
Main : jdbc:mariadb://localhost:3306/client_project

When spring invoke this constructor, url attribute is null ! If @Value properties must be read before instanciating beans, so the url must be set and different from null.

Isn't it ?

Is something wrong with my code? or with my understanding of bean lifecycle?

1

1 Answers

4
votes

When spring invoke this constructor, url attribute is null ! if @Value properties must be read before instanciating beans, so the url must be set and different from null. isn't it ?

This is not how it works, if constructor of ReadValueFromFile require @Value then only Spring will guarantee that before instantiating ReadValueFromFile the url value is available, otherwise Spring instantiate ReadValueFromFile using default constructor and then by calling setter method of url property it'll inject the value.

Hence, during constructor run you will not see the value.

There is nothing wrong with your code.

You need to understand, how Spring injects the dependencies(or values):

  1. Constructor inject - means dependency/value must be present during dependent instantiation for injection
  2. Setter injection - means dependency/value is not required during dependent instantiation but will be injected later using setter method
  3. Field injection - means dependency/value is not required during dependent instantiation but will be injected later using reflection