前言
笔者前些日子读Spring文档的时候发现了一个有意思的小知识,做了一个小测试分享给大家。我这里说的生命周期的回调,并不是Spring bean的生命周期。Bean的生命周期贯彻整个Spring容器的启动与销毁,是一个很长的过程。这里所说的是生命周期的回调,什么是回调呢?简单来说就是在类创建的时候或者销毁的时候必须要调用的方法。我们举个例子try-catch-finally这个语法块大家都用过,这个回调方法就很像finally块的逻辑,无论上面的逻辑是怎样的,finally里面的内容一定会被执行。就是说执行初始化的时候调用的方法,销毁的时候也会调用这个方法,官网上关于这部分的介绍就叫做【Lifecycle Callbacks】。以下引用的部分都是来自官方文档。
Lifecycle Callbacks
先看下官网怎么说的:
To interact with the container’s management of the bean lifecycle, you can implement the Spring InitializingBean and DisposableBean interfaces. The container calls afterPropertiesSet() for the former and destroy() for the latter to let the bean perform certain actions upon initialization and destruction of your beans.
大意就是,Spring官方一共给我们提供了两种回调方法:一个是初始化回调InitializingBean提供了一个afterPropertiesSet()方法用于bean的初始化的时候调用;另一个是销毁的回调DisposableBean 提供一个destroy()用于销毁的时候调用。但是官方给的并不只是这一种,而且给了自定义实现的办法,所以这篇文章的目的就是说清楚,这几种方法都是怎么用的。
官方提供的实现种类
Combining Lifecycle Mechanisms
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
用户自定义实现,也就是xml中自定义。
• The @PostConstruct and @PreDestroy annotations. You can combine these mechanisms to control a given bean.
使用注解实现
注意这句话You can combine these mechanisms to control a given bean.,翻一下就是你可以混着使用这些机制去控制一个bean。也就是说哪种熟悉用哪种,混着用也没关系,所以说Spring这个公司真实太良心了。那么我们稍后就进入使用的例子。
接口型
Initialization Callbacks
这里就是官方提提供的第一种,实现接口型【Initialization Callbacks】。我们线看下回调方法的效果。假设我们有Appconfig一个配置类,一个接口DemoDao,一个实现类DemoDaoImpl这个类实现InitializingBean ,一个测试类Test。
@Configuration
@ComponentScan("com.example.callback")
public class Appconfig {
}public interface DemoDao {
}@@Repository(“dao”)
public class DemoDaoImpl implements DemoDao, InitializingBean {
public DemoDaoImpl() {
System.out.println("DemoDaoImpl Constructor");
}
@Override
public void afterPropertiesSet() throws Exception {
//初始化如果有些东西不方便放在构造方法里可以放在这里面做
System.out.println("DemoDaoImpl InitializingBean");
}
}public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext anno=new AnnotationConfigApplicationContext(Appconfig.class);
}
}此时如果直接运行Test中的main()方法,那么打印的一定是两行:DemoDaoImpl Constructor和DemoDaoImpl InitializingBean。为什么要有这个东西呢,因为初始化如果有些东西不方便放在构造方法里可以放在这里面做,比如要读一些配置文件之类的。这就好像一个钩子,一旦类初始化了以后立即勾起这个方法的调用。
Destruction Callbacks
Implementing the org.springframework.beans.factory.DisposableBean interface lets a bean get a callback when the container that contains it is destroyed. The DisposableBean interface specifies a single method:
这里大意就是说:销毁自然就是使用DisposableBean 这个接口的destroy()方法去实现。但是这个例子怎么演示,笔者没有想好,如果有直到的同学,麻烦也告知一下,所以下面的例子演示都会以init为主。
@Repository
public class DemoDaoImpl2 implements DemoDao, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("DemoDaoImpl Destroyed");
}
}XML型
当然还是先看官网咋说的【Default Initialization and Destroy Methods】:
When you write initialization and destroy method callbacks that do not use the Spring-specific InitializingBean and DisposableBean callback interfaces, you typically write methods with names such as init(), initialize(), dispose(), and so on. Ideally, the names of such lifecycle callback methods are standardized across a project so that all developers use the same method names and ensure consistency.
You can configure the Spring container to “look” for named initialization and destroy callback method names on every bean. This means that you, as an application developer, can write your application classes and use an initialization callback called init(), without having to configure an init-method=“init” attribute with each bean definition. The Spring IoC container calls that method when the bean is created (and in accordance with the standard lifecycle callback contract described previously). This feature also enforces a consistent naming convention for initialization and destroy method callbacks.
Suppose that your initialization callback methods are named init() and your destroy callback methods are named destroy(). Your class then resembles the class in the following example:
上面的大意就是说,如果觉得使用Spring的接口依赖性太强。不想用这个两个接口,Spring也提供了别的方式,可以自定义自己的初始化方法,只要在xml文件里配置好就没问题。这里说的默认的实例化方法,其实就是在XML里面给<bean>配置init-method="init"。除了针对单个的<bean>定义,也可以在<beans>中配置一个全局初始化方法,使用的参数是default-init-method。
注意:一旦给单个<bean>配置了方法,就会把全局的配置覆盖掉。我们还是以DemoImpl为例:
@Repository(“dao”)
public class DemoDaoImpl implements DemoDao{
public void initGlobal(){
System.out.println("全局初始化方法");
}
public void initSingle(){
System.out.println("局部初始化方法");
}
}XML配置文件中:
<beans default-init-method=" initGlobal"><!--这里定义默认的方法,全局定义-->
<bean id="dao" class="com.example.demo.DemoDaoImpl" init-method="initSingle">
</bean> <!--这里init_singl就被定义为一个初始化方法了-->
</beans>要注意,这里可以自定义的,你可以不叫init_singl,也可以直接叫test,或者阿猫阿狗都可以的。只要xml配置和方法名一致,就没问题。现在直接运行Test的话,就会打印得是"局部初始化方法",因为<bean>内部的设置把全局的屏蔽掉了。所以如果我们把<bean>里面配置的init-method="init_singl"删掉,就会打印"全局初始化方法"。
当然你要定义销毁也可以用default-destroy-method或者destroy-method这两个参数定制,用法和init的一样,不多说了。
注解型:
找到官方文档【Combining Lifecycle Mechanisms】
Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows:
• Methods annotated with @PostConstruct.Destroy methods are called in the same order:
• Methods annotated with @PreDestroy
官网这里说的可以说是十分的简单明了。初始化用@PostConstruct注解,销毁的时候用@PreDestroy这个注解。而且经过测试,笔者可以说十分推崇这种基于注解的方法。首先笔者喜欢注解,非常讨厌配置xml文件。其次因为自定义非常的方便,不要我们再有多余的配置。那么还是以DemoDaoImpl为例子:
@Repository("dao")
public class DemoDaoImpl implements InitializingBean {
public DemoDaoImpl() {
//构造方法打印
System.out.println("DemoDaoImpl Constructor");
}
@PostConstruct //自定义init注解打印
public void initTest(){
System.out.println("DemoDaoImpl PostConstruct");
}
@Override //实现spring接口打印
public void afterPropertiesSet() throws Exception {
System.out.println("DemoDaoImpl InitializingBean");
}
@PreDestroy //自定义destroy注解打印
public void destoryTest(){
System.out.println("DemoDaoImpl PreDestroy");
}
}这里运行test一定打印三个DemoDaoImpl Constructor,DemoDaoImpl PostConstruct和DemoDaoImpl InitializingBean,也侧面印证了官网说的三种混用没有问题。
















