Init method in Spring Controller (annotation version)
Alternatively you can have your class implement the InitializingBean
interface to provide a callback function (afterPropertiesSet()
) which the ApplicationContext will invoke when the bean is constructed.
There are several ways to intercept the initialization process in Spring. If you have to initialize all beans and autowire/inject them there are at least two ways that I know of that will ensure this. I have only testet the second one but I belive both work the same.
If you are using @Bean you can reference by initMethod, like this.
@Configurationpublic class BeanConfiguration { @Bean(initMethod="init") public BeanA beanA() { return new BeanA(); }}public class BeanA { // method to be initialized after context is ready public void init() { }}
If you are using @Component you can annotate with @EventListener like this.
@Componentpublic class BeanB { @EventListener public void onApplicationEvent(ContextRefreshedEvent event) { }}
In my case I have a legacy system where I am now taking use of IoC/DI where Spring Boot is the choosen framework. The old system brings many circular dependencies to the table and I therefore must use setter-dependency a lot. That gave me some headaches since I could not trust @PostConstruct since autowiring/injection by setter was not yet done. The order is constructor, @PostConstruct then autowired setters. I solved it with @EventListener annotation which wil run last and at the "same" time for all beans. The example shows implementation of InitializingBean aswell.
I have two classes (@Component) with dependency to each other. The classes looks the same for the purpose of this example displaying only one of them.
@Componentpublic class BeanA implements InitializingBean { private BeanB beanB; public BeanA() { log.debug("Created..."); } @PostConstruct private void postConstruct() { log.debug("@PostConstruct"); } @Autowired public void setBeanB(BeanB beanB) { log.debug("@Autowired beanB"); this.beanB = beanB; } @Override public void afterPropertiesSet() throws Exception { log.debug("afterPropertiesSet()"); } @EventListener public void onApplicationEvent(ContextRefreshedEvent event) { log.debug("@EventListener"); } }
This is the log output showing the order of the calls when the container starts.
2018-11-30 18:29:30.504 DEBUG 3624 --- [ main] com.example.demo.BeanA : Created...2018-11-30 18:29:30.509 DEBUG 3624 --- [ main] com.example.demo.BeanB : Created...2018-11-30 18:29:30.517 DEBUG 3624 --- [ main] com.example.demo.BeanB : @Autowired beanA2018-11-30 18:29:30.518 DEBUG 3624 --- [ main] com.example.demo.BeanB : @PostConstruct2018-11-30 18:29:30.518 DEBUG 3624 --- [ main] com.example.demo.BeanB : afterPropertiesSet()2018-11-30 18:29:30.518 DEBUG 3624 --- [ main] com.example.demo.BeanA : @Autowired beanB2018-11-30 18:29:30.518 DEBUG 3624 --- [ main] com.example.demo.BeanA : @PostConstruct2018-11-30 18:29:30.518 DEBUG 3624 --- [ main] com.example.demo.BeanA : afterPropertiesSet()2018-11-30 18:29:30.607 DEBUG 3624 --- [ main] com.example.demo.BeanA : @EventListener2018-11-30 18:29:30.607 DEBUG 3624 --- [ main] com.example.demo.BeanB : @EventListener
As you can see @EventListener is run last after everything is ready and configured.