Spring - Why init-method or @PostConstruct is to be used instead of InitializingBean
Published On: 2019/11/04
Why spring provides initMethod attribute in the @Bean annotation though an interface InitializingBean is part of the spring framework.
Spring framework provides many Lifecycle Callbacks to support the software development much easier. The InitializingBean callback method, afterPropertiesSet ,will be called after the container has set all necessary properties on the bean. Spring team suggest not to use the InitializingBean bean class as it unnecessarily couples the code to Spring. They suggest to use the @PostConstruct JSR-250 annotation or a POJO initialization method (@Bean attribute initMethod).
I have used first 3 beans in the below configuration to explain the 3 ways of invoking post bean initialization callback and the last bean initOrderofExecutionBean to explain the order of execution.
@Configuration
public class BeanConfig {
@Bean
public Jsr250SampleBean jsr250SampleBean(){
return new Jsr250SampleBean();
}
@Bean(initMethod = "init")
public PojoInitSampleBean pojoInitSampleBean(){
return new PojoInitSampleBean();
}
@Bean
public SpringwayInitializingBean springwayInitializingBean(){
return new SpringwayInitializingBean();
}
@Bean(initMethod = "init")
public InitOrderofExecutionBean initOrderofExecutionBean(){return new InitOrderofExecutionBean();}
}
@PostConstruct
This annotation marks a method that must be executed after dependency injection is performed on the class.
public class Jsr250SampleBean {
private final static Logger LOG = LoggerFactory.getLogger(Jsr250SampleBean.class);
public Jsr250SampleBean(){
LOG.info("Inside Constructor");
}
@PostConstruct
public void postConstruct(){
LOG.info("Inside @PostConstruct method");
}
}
initMethod
public class PojoInitSampleBean {
private final static Logger LOG = LoggerFactory.getLogger(PojoInitSampleBean.class);
public PojoInitSampleBean(){
LOG.info("Inside Constructor");
}
public void init(){
LOG.info("Inside bean init method");
}
}
InitializingBean
public class SpringwayInitializingBean implements InitializingBean {
private final static Logger LOG = LoggerFactory.getLogger(SpringwayInitializingBean.class);
@Override
public void afterPropertiesSet() throws Exception {
LOG.info("Inside afterPropertiesSet method");
}
}
Order of execution
public class InitOrderofExecutionBean implements InitializingBean {
private final static Logger LOG = LoggerFactory.getLogger(InitOrderofExecutionBean.class);
public InitOrderofExecutionBean(){
LOG.info("Inside Constructor");
}
@PostConstruct
public void postConstruct(){
LOG.info("Inside @PostConstruct method");
}
public void init(){
LOG.info("Inside bean init method");
}
@Override
public void afterPropertiesSet() throws Exception {
}
}
As you can see in the below output, first bean is created using consturctor and then the PostConstruct method is invoked and after that the init method of the bean is invoked.
2019-11-04 07:30:51.773 INFO 4364 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2148 ms
2019-11-04 07:30:51.841 INFO 4364 --- [ main] c.a.s.jsr250.InitOrderofExecutionBean : Inside Constructor
2019-11-04 07:30:51.842 INFO 4364 --- [ main] c.a.s.jsr250.InitOrderofExecutionBean : Inside @PostConstruct method
2019-11-04 07:30:51.842 INFO 4364 --- [ main] c.a.s.jsr250.InitOrderofExecutionBean : Inside afterPropertiesSet method
2019-11-04 07:30:51.843 INFO 4364 --- [ main] c.a.s.jsr250.InitOrderofExecutionBean : Inside bean init method
2019-11-04 07:30:52.035 INFO 4364 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
Conclusion
If possible it is always better to avoid coupling to the underlying frameworks. To know the recommendation of Spring team on bean initialization please read the section Initialization Callbacks