Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpringBoot - Order of Bean creation and PostConstruct initialization

I have a maven multimodule SpringBoot web application. I have a submodule, called config-module which has a configuration class:

@Configuration
public class PropertiesConfig {

    @Bean
    public YamlPropertiesFactoryBean errorPropertiesFromYamlFile() {
        final YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
        yaml.setResources(new ClassPathResource("errorMessages.yml"));
        return yaml;
    }

}

I have a web-app-module maven module, which has the previous config-module as a dependency, and as an imported spring application.

In this main module, I also have a configuration class which loads new properties:

@Configuration
public class WebPropertiesConfig {

    @Bean
    public YamlPropertiesFactoryBean webPropertiesFromYamlFile() {
        final YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
        yaml.setResources(new ClassPathResource("webProperties.yml"));
        return yaml;
    }

}

And in this module I also have a class like this:

@Component
@ConfigurationProperties(prefix = "webpart")
public class ConfigPropertiesMapper {

    @PostConstruct
    public void init() {
        //do something here
    }

}

And I don't know where it comes from, but the actual order of initialization is this (I checked it within debug mode):

  1. PropertiesConfig.errorPropertiesFromYamlFile() bean creation from config-module
  2. ConfigPropertiesMapper.init() PostConstruct initialization from web-app-module
  3. WebPropertiesConfig.webPropertiesFromYamlFile() bean creation from web-app-module

Why is that? And how could I set the order to this?:

  1. PropertiesConfig.errorPropertiesFromYamlFile()
  2. WebPropertiesConfig.webPropertiesFromYamlFile()
  3. ConfigPropertiesMapper.init()

I tried with the @Order, @Qualifier, @Primary annotations, but I could not solve this.

I know one more annotation: @DependsOn. But honestly, I don't want to use it, because then I need to add this annotation to every methods which has @PostConstruct on it.

like image 215
victorio Avatar asked Aug 05 '26 13:08

victorio


2 Answers

From the API documentation

"While such order values may influence priorities at injection points, please be aware that they do not influence singleton startup order which is an orthogonal concern determined by dependency relationships and @DependsOn declarations (influencing a runtime-determined dependency graph)."

You need to either a @DependsOn annotation to control creation order.

Or else call all the init methods in one bean so you can control the order. If you inject the other beans you will be sure they have finished creation.

Something like:

@Component
public class InitBean {

   @Autowired
   privaPropertiesConfig propertiesConfig;

   @Autowired
   private WebPropertiesConfig webPropertiesConfig;

   @Autowired
   private ConfigPropertiesMapper configPropertiesMapper;

   @PostConstruct
   public void init() {
       propertiesConfig.errorPropertiesFromYamlFile()
       webPropertiesConfig.webPropertiesFromYamlFile()
       configPropertiesMapper.init()    
    }
}

However you should probably add all your properties into one class, spring will find what it can, ignore what it can't and any values duplicate values in errroMessages will be overriden by webProperties.

@Component
@PropertySource(value={ "classpath:errorMessages.yml", "classpath:webProperties.yml"}, ignoreResourceNotFound="true))
@ConfigurationProperties(prefix = "webpart")
public class ConfigPropertiesMapper {
   ...    
}
like image 177
Essex Boy Avatar answered Aug 07 '26 04:08

Essex Boy


There are different mechanisms of bean initialization (not bean creation) in Spring/Boot. They can be used regardless of bean dependencies, if desired.

The order (mid. 2020 with Spring Boot 2.3.2) is:

  1. direct bean initialization with @PostConstruct or InitializingBean
  2. SmartInitializingSingletons
  3. SmartLifecycle beans
  4. ApplicationStartedEvent is triggered
  5. ApplicationReadyEvent is triggered

(there are other events too, of course)

like image 45
leonid Avatar answered Aug 07 '26 03:08

leonid