Init method in Spring Controller (annotation version)

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?

151895 次浏览

你可以用

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

或者,您可以让您的类实现 InitializingBean接口来提供一个回调函数(afterPropertiesSet()) ,当构造 bean 时 ApplicationContext 将调用该函数。

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
}


}

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.

如果使用@Bean,可以通过 initMethod 进行引用,如下所示。

@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() {
}


}

如果您使用的是@Component,您可以像这样使用@EventListener 进行注释。

@Component
public class BeanB {


@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
}
}

在我的例子中,我有一个遗留系统,我现在使用 IoC/DI,其中 Spring Boot 是选择的框架。旧系统给表带来了许多循环依赖关系,因此我必须大量使用 setter 依赖关系。这让我有些头疼,因为我不能信任@PostConstruction,因为 setter 的自动装配/注入还没有完成。顺序是构造函数,然后是@PostConstruction 自动连接的 setter。我使用@EventListener 注释解决了这个问题,该注释将最后运行,并在“同一时间”运行所有 bean。该示例还显示了 InitializingBean 的实现。

我有两个相互依赖的类(@Component)。对于本示例只显示其中一个类的目的,这些类看起来是相同的。

@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");
}
}

这是显示容器启动时调用顺序的日志输出。

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.

@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");
}

}

在类中,可以声明一个名为 init ()的方法。

请参阅: 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