Spring中的Bean从创建到销毁经历了一个又一个阶段,在这些阶段中,我们可以通过某些方法来控制Bean的创建、Bean的销毁。
在Spring的官方文档中,有这么一段话
As of Spring 2.5, you have three options for controlling bean lifecycle behavior: the InitializingBean and DisposableBean callback interfaces; custom init() and destroy() methods; and the @PostConstruct and @PreDestroy annotations. You can combine these mechanisms to control a given bean
具体意思就是说:在Spring2.5以后,我们有三种方式来控制Bean的生命周期管理。
1.通过InitializingBean和DisposableBean接口
2.Bean的init()和destroy()方法
3.@PostConstruct和@PreDestroy注解
那我们就来看下这三种方式的实现
1)我们首先来创建一个类,命名为LifeCycleBean,实现这两个接口,并实现其方法
public class LifeCycleBean implements Serializable , InitializingBean, DisposableBean {
private static final long serialVersionUID = 2731651017595722776L;
public void destroy() throws Exception {
System.out.println("DisposableBean destroy...");
}
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean init...");
}
}
2)在beans.xml中定义该Bean
3)测试类测试生命周期方法
@Test
public void testXml(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
LifeCycleBean lifeCycleBean = (LifeCycleBean) applicationContext.getBean("lifeCycleBean");
applicationContext.close();
}
// res
InitializingBean init...
DisposableBean destroy...
总结:在LifeCycleBean被获取的时候,afterPropertiesSet()方法被调用;在容器关闭之前,destroy()方法被调用
这种方式大家应该都比较了解了,在之前的文章中我们已经使用过这两个方法,这里再简单演示一下。
1)在LifeCycleBean.java中添加方法xmlInit() xmlDestroy()
public void xmlDestroy() {
System.out.println("xml destroy...");
}
public void xmlInit() {
System.out.println("xml init...");
}
2)beans.xml中定义的LifeCycleBean添加init-method和destroy-method指向xmlInit()和xmlDestroy()
3)测试Bean
总结:同1中的两个接口实现了同样的结果
1)这两个怎么用呢?具体如下:
// 在LifeCycleBean中添加以下即可
@PostConstruct
public void postConstruct() {
System.out.println("annotation init ...");
}
@PreDestroy
public void preDestroy() {
System.out.println("annotation destroy...");
}
2)beans.xml定义如前,测试代码如前,结果如下所示:
// 结果是空的,好尴尬
疑问:为什么是空的呢?为什么在main方法中通过容器获取Bean的这种方式没有执行postConstruct()方法和preDestroy()方法呢?
答疑:我们可以看到这两个是注解类的,我们之前Bean的定义全都是通过xml定义的方式来实现的。说明我们目前的Spring容器还没有辨识注解的能力。
扩展:在目前的开发项目中,我们一般都是通过注解来自动注入Bean,如果@Controller @Service @Component之类的注解,但是这个有一个前提条件是我们必须要先让Spring有识别注解的能力,这样就需要在beans.xml文件中添加以下内容:
3)添加了上述注解之后,我们再运行一次,结果如下:
annotation init ...
InitializingBean init...
xml init...
annotation destroy...
DisposableBean destroy...
xml destroy...
既然一个Bean的初始化和销毁方法有这么几种方式,那么在实际运用中我们应该如何选择呢?Spring已经给出了相关建议
// init相关建议
It is recommended that you do not use the InitializingBean interface because it unnecessarily couples the code to Spring. Alternatively, use the @PostConstruct annotation or specify a POJO initialization method. In the case of XML-based configuration metadata, you use the init-method attribute to specify the name of the method that has a void no-argument signature. With Java config, you use the initMethod attribute of @Bean
// destroy相关建议
It is recommended that you do not use the DisposableBean callback interface because it unnecessarily couples the code to Spring. Alternatively, use the @PreDestroy annotation or specify a generic method that is supported by bean definitions. With XML-based configuration metadata, you use the destroy-method attribute on the . With Java config, you use the destroyMethod attribute of @Bean
总结下来就是:建议在项目中使用@PostConstruct和@PreDestroy,因为InitializingBean和DisposableBean与代码强耦合。如果非Web项目,我们也可以使用
如果一个Bean这几种生命周期方法都有的话,那么执行顺序应该是怎样的呢?
Spring同样也给出了答案
Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows:
// 初始化方法调用顺序
1.Methods annotated with @PostConstruct
2.afterPropertiesSet() as defined by the InitializingBean callback interface
3.A custom configured init() method
Destroy methods are called in the same order:
// 销毁方法调用顺序
1.Methods annotated with @PreDestroy
2.destroy() as defined by the DisposableBean callback interface
3.A custom configured destroy() method
以上三种Bean生命周期管理的方式,我们可以自由选择,一般来说从注解和Spring接口中选择一种,如果我们不想与Spring强耦合,那么可以选择注解方式
https://docs.spring.io/spring/docs/4.3.23.RELEASE/spring-framework-reference/htmlsingle/
代码地址:https://github.com/kldwz/springstudy