Init method in Spring Controller (annotation version)

JavaSpringAnnotationsController

Java Problem Overview


I'm converting a controller to the newer annotation version. In the old version I used to specify the init method in springmvc-servlet.xml using:

<beans>
    <bean id="myBean" class="..." init-method="init"/>
</beans>

How can I specify the init method using the annotation version?

Java Solutions


Solution 1 - Java

You can use

@PostConstruct
public void init() {
   // ...
}

Solution 2 - Java

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.

Solution 3 - Java

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.

@Configuration
public 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.

@Component
public 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.

@Component
public 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 beanA
2018-11-30 18:29:30.518 DEBUG 3624 --- [           main] com.example.demo.BeanB                   : @PostConstruct
2018-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 beanB
2018-11-30 18:29:30.518 DEBUG 3624 --- [           main] com.example.demo.BeanA                   : @PostConstruct
2018-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                   : @EventListener
2018-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.

Solution 4 - Java

@PostConstruct、implement InitializingBean、specify init-method they have call orders. So you can't use them to replace init-method. You can try this:

@Bean(initMethod = "init")
public MyBean mybean() {
	return new MyBean();
}



class MyBean {
public void init() {
	System.out.println("MyBean init");
}

}

in your class, you can declare a method named init().

Refer to: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#:~:text=Multiple%20lifecycle%20mechanisms%20configured%20for%20the%20same%20bean%2C%20with%20different%20initialization%20methods%2C%20are%20called%20as%20follows%3A

Solution 5 - Java

public class InitHelloWorld implements BeanPostProcessor {

   public Object postProcessBeforeInitialization(Object bean,
             String beanName) throws BeansException {
       System.out.println("BeforeInitialization : " + beanName);
       return bean;  // you can return any other object as well
   }

   public Object postProcessAfterInitialization(Object bean,
             String beanName) throws BeansException {
       System.out.println("AfterInitialization : " + beanName);
       return bean;  // you can return any other object as well
   }

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKrt_MaltaView Question on Stackoverflow
Solution 1 - JavaJohan SjöbergView Answer on Stackoverflow
Solution 2 - Javamatt bView Answer on Stackoverflow
Solution 3 - JavaAvecView Answer on Stackoverflow
Solution 4 - JavacooooopdView Answer on Stackoverflow
Solution 5 - JavaYasir Shabbir ChoudharyView Answer on Stackoverflow