Spring Bean 生命周期——初始化和销毁
在 Spring Bean 的生命周期中,有两个核心环节,那就是初始化和销毁,下面我们看看都有哪几种方式指定对应的初始化或销毁操作,以及它们的作用原理。
多种方式概览
在 @Bean 注解中指定参数:
initMethod:自定义初始化逻辑(如果用 xml 文件指定,就是 init-method 参数)
destroyMethod:自定义销毁逻辑(如果用 xml 文件指定,就是 destroy-method 参数)
实现 InitializingBean 和 DisposableBean 接口:
实现 InitializingBean 接口的 afterPropertiesSet 方法:自定义初始化逻辑
实现 DisposableBean 接口的 destroy 方法:自定义销毁逻辑
利用 JSR250 规范中的注解(注意这两个注解都是 javax 包中的,而非 Spring 自带):
@PostConstruct:自定义初始化逻辑
@PreDestroy:自定义销毁逻辑
自定义后置处理器:
实现 postProcessBeforeInitialization 方法:自定义初始化逻辑
实现 postProcessAfterInitialization 方法:自定义销毁逻辑
几种方式初体验
首先我们创建一个 maven 项目,Spring 版本采用 5.0.11.RELEASE。Bean 的定义用 javaConfig 的方式。
先创建一个测试类:
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author xiaoxi666
* @date 2020-05-28 18:16
*/
public class MyTest {
@Test
public void test_01() {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MyConfiguration.class);
System.out.println("容器创建完毕");
System.out.println("=============================");
applicationContext.close();
System.out.println("容器销毁完毕");
}
}
接着开始体验各种方式:
1. 在 @Bean 注解中指定参数
创建 bean 对应的 class:
package bean;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
public class MyBeanWithInitMethodAndDestroyMethod {
private static final String NAME = MyBeanWithInitMethodAndDestroyMethod.class.getSimpleName();
public MyBeanWithInitMethodAndDestroyMethod() {
System.out.print(NAME + ": ");
System.out.println("constructor");
}
public void myInitMethod() {
System.out.print(NAME + ": ");
System.out.println("@Bean#initMethod");
}
public void myDestroyMethod() {
System.out.print(NAME + ": ");
System.out.println("@Bean#destroyMethod");
}
}
对应的配置类:
import bean.MyBeanWithInitMethodAndDestroyMethod;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
@Configuration
public class MyConfiguration {
@Bean(initMethod = "myInitMethod", destroyMethod = "myDestroyMethod")
public MyBeanWithInitMethodAndDestroyMethod myBeanWithInitMethodAndDestroyMethod() {
return new bean.MyBeanWithInitMethodAndDestroyMethod();
}
}
执行测试类,输出:
MyBeanWithInitMethodAndDestroyMethod: constructor
MyBeanWithInitMethodAndDestroyMethod: @Bean#initMethod
容器创建完毕
=============================
MyBeanWithInitMethodAndDestroyMethod: @Bean#destroyMethod
容器销毁完毕
2. 实现 InitializingBean 和 DisposableBean 接口
创建 bean 对应的 class:
package bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
public class MyBeanImplementsInitializingBeanAndDisposableBean implements InitializingBean, DisposableBean {
private static final String NAME = MyBeanImplementsInitializingBeanAndDisposableBean.class.getSimpleName();
public MyBeanImplementsInitializingBeanAndDisposableBean() {
System.out.print(NAME + ": ");
System.out.println("constructor");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.print(NAME + ": ");
System.out.println("InitializingBean#afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
System.out.print(NAME + ": ");
System.out.println("DisposableBean#destroy");
}
}
对应的配置类:
import bean.MyBeanImplementsInitializingBeanAndDisposableBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
@Configuration
public class MyConfiguration {
@Bean
public MyBeanImplementsInitializingBeanAndDisposableBean myBeanImplementsInitializingBean() {
return new bean.MyBeanImplementsInitializingBeanAndDisposableBean();
}
}
执行测试类,输出:
MyBeanImplementsInitializingBeanAndDisposableBean: constructor
MyBeanImplementsInitializingBeanAndDisposableBean: InitializingBean#afterPropertiesSet
容器创建完毕
=============================
MyBeanImplementsInitializingBeanAndDisposableBean: DisposableBean#destroy
容器销毁完毕
3. 利用 JSR250 规范中的注解
创建 bean 对应的 class:
package bean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
public class MyBeanWithPostConstructAndPreDestroy {
private static final String NAME = MyBeanWithPostConstructAndPreDestroy.class.getSimpleName();
public MyBeanWithPostConstructAndPreDestroy() {
System.out.print(NAME + ": ");
System.out.println("constructor");
}
@PostConstruct
public void myPostConstructMethod() throws Exception {
System.out.print(NAME + ": ");
System.out.println("@PostConstruct");
}
@PreDestroy
public void myPreDestroyMethod() throws Exception {
System.out.print(NAME + ": ");
System.out.println("@PreDestroy");
}
}
对应的配置类:
import bean.MyBeanImplementsInitializingBeanAndDisposableBean;
import bean.MyBeanWithInitMethodAndDestroyMethod;
import bean.MyBeanWithManyMethod;
import bean.MyBeanWithPostConstructAndPreDestroy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
@Configuration
public class MyConfiguration {
@Bean
public MyBeanWithPostConstructAndPreDestroy myBeanWithPostConstructAndPreDestroy() {
return new MyBeanWithPostConstructAndPreDestroy();
}
}
执行测试类,输出:
MyBeanWithPostConstructAndPreDestroy: constructor
MyBeanWithPostConstructAndPreDestroy: @PostConstruct
容器创建完毕
=============================
MyBeanWithPostConstructAndPreDestroy: @PreDestroy
容器销毁完毕
4. 自定义后置处理器
package processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
private static final String NAME = MyBeanPostProcessor.class.getSimpleName();
public MyBeanPostProcessor() {
System.out.print(NAME + ": ");
System.out.println("constructor");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.print(NAME + ": ");
System.out.println("BeanPostProcessor#postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.print(NAME + ": ");
System.out.println("BeanPostProcessor#postProcessAfterInitialization");
return bean;
}
}
对应的配置类(注意添加扫描路径,参见程序中的 @ComponentScan 注解):
import bean.MyBeanWithPostConstructAndPreDestroy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
@ComponentScan("processor")
@Configuration
public class MyConfiguration {
//这里我们并没有配置bean,先观察一下后置处理器会干什么
}
执行测试类,输出:
MyBeanPostProcessor: constructor
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
容器创建完毕
=============================
容器销毁完毕
上面输出的内容是 Spring 容器中的其他组件。
我们改一下配置类,随便加一个 bean,再看看:
import bean.MyBeanWithInitMethodAndDestroyMethod;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
@ComponentScan("processor")
@Configuration
public class MyConfiguration {
@Bean(initMethod = "myInitMethod", destroyMethod = "myDestroyMethod")
public MyBeanWithInitMethodAndDestroyMethod myBeanWithInitMethodAndDestroyMethod() {
return new MyBeanWithInitMethodAndDestroyMethod();
}
}
输出:
MyBeanPostProcessor: constructor
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanWithInitMethodAndDestroyMethod: constructor
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanWithInitMethodAndDestroyMethod: @Bean#initMethod
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
容器创建完毕
=============================
MyBeanWithInitMethodAndDestroyMethod: @Bean#destroyMethod
容器销毁完毕
可以看到,后置处理器会在我们的初始化方法执行前后分别调用。
其他类型的 Bean 同理,这里贴一下输出:
MyBeanPostProcessor: constructor
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanImplementsInitializingBeanAndDisposableBean: constructor
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanImplementsInitializingBeanAndDisposableBean: InitializingBean#afterPropertiesSet
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
容器创建完毕
=============================
MyBeanImplementsInitializingBeanAndDisposableBean: DisposableBean#destroy
容器销毁完毕
MyBeanPostProcessor: constructor
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanWithPostConstructAndPreDestroy: constructor
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanWithPostConstructAndPreDestroy: @PostConstruct
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
容器创建完毕
=============================
MyBeanWithPostConstructAndPreDestroy: @PreDestroy
容器销毁完毕
小结
至此我们初步明白了几种方式的作用原理:
多种方式同时使用时,顺序是怎样的?
同样,我们先通过实例体验下:
创建 bean 对应的 class,它同时使用了三种方式:
package bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* @author xiaoxi666
* @date 2020-05-28 19:53
*/
public class MyBeanWithManyMethod implements InitializingBean, DisposableBean {
private static final String NAME = MyBeanWithManyMethod.class.getSimpleName();
public MyBeanWithManyMethod() {
System.out.print(NAME + ": ");
System.out.println("constructor");
}
/***************************@Bean中的方法*******************************/
public void myInitMethod() {
System.out.print(NAME + ": ");
System.out.println("@Bean#initMethod");
}
public void myDestroyMethod() {
System.out.print(NAME + ": ");
System.out.println("@Bean#destroyMethod");
}
/****************InitializingBean和DisposableBean中的方法*****************/
@Override
public void afterPropertiesSet() throws Exception {
System.out.print(NAME + ": ");
System.out.println("InitializingBean#afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
System.out.print(NAME + ": ");
System.out.println("DisposableBean#destroy");
}
/****************@PostConstruct和@PreDestroy*****************/
@PostConstruct
public void myPostConstructMethod() throws Exception {
System.out.print(NAME + ": ");
System.out.println("@PostConstruct");
}
@PreDestroy
public void myPreDestroyMethod() throws Exception {
System.out.print(NAME + ": ");
System.out.println("@PreDestroy");
}
}
配置类:
import bean.MyBeanWithManyMethod;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaoxi666
* @date 2020-05-28 18:09
*/
@ComponentScan("processor")
@Configuration
public class MyConfiguration {
@Bean(initMethod = "myInitMethod", destroyMethod = "myDestroyMethod")
public MyBeanWithManyMethod myBeanWithManyMethod() {
return new MyBeanWithManyMethod();
}
}
输出:
MyBeanPostProcessor: constructor
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
MyBeanWithManyMethod: constructor
MyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitialization
MyBeanWithManyMethod: @PostConstruct
MyBeanWithManyMethod: InitializingBean#afterPropertiesSet
MyBeanWithManyMethod: @Bean#initMethod
MyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization
容器创建完毕
=============================
MyBeanWithManyMethod: @PreDestroy
MyBeanWithManyMethod: DisposableBean#destroy
MyBeanWithManyMethod: @Bean#destroyMethod
容器销毁完毕
可以看到三种方式的顺序如图所示:
那么这个顺序是在哪里决定的呢?来看看源码:
先看初始化
其中:
第一步和第三步中的后置处理器包括两个东东。
我们自定义的后置处理器
@PostConstruct 和 @PreDestroy 两个注解也使用后置处理器,只不过它们使用的是 Spring 自带的后置处理器,也即 CommonAnnotationBeanPostProcessor,它在 Spring 容器初始化时就被注册进来了。
第二步中的自定义初始化方法也包括两个东东。
InitializingBean#afterPropertiesSet
@Bean#initMetho
这里还有一个遗留点:后置处理器包括我们自己定义的后置处理器和 @PostConstruct 对应的后置处理器,它俩的顺序如何保证?
让我们看看后置处理器的注册源码:
所以我们可以确信,自定义的后置处理器会优先于框架自带的后置处理器执行。其实,在 addBeanPostProcessor 方法中有明确的注释:
再看销毁
至此,我们对初始化和销毁流程就了然于胸了。
资源
项目已上传至github,这个仓库会更新一些 Spring 学习的记录。
文件结构:
├── pom.xml
└── src
├── main
│ ├── java
│ │ ├── MyConfiguration.java ## 配置类,功能与xml相同
│ │ ├── bean
│ │ │ ├── MyBeanImplementsInitializingBeanAndDisposableBean.java ## 实现InitializingBean和DisposableBean接口
│ │ │ ├── MyBeanWithInitMethodAndDestroyMethod.java ## 在@Bean注解中指定参数
│ │ │ ├── MyBeanWithManyMethod.java ## 多种方式同时使用
│ │ │ └── MyBeanWithPostConstructAndPreDestroy.java ## 利用JSR250规范中的注解
│ │ └── processor
│ │ └── MyBeanPostProcessor.java ## 自定义后置处理器
│ └── resources
└── test
└── java
└── MyTest.java ## 测试类
扩展
多种初始化方式发生的时机不同,但实现的效果类似。
最好不要将多种方式混用,尽量保持代码的简单性。
我们最常用的方式是在创建 bean 时就指定 initMethod 和 destroyMethod。
@PostConstruct 和 @PreDestroy 注解来源于 Javax 包,而非 Spring 自带。
后置处理器的功能最为强大,Spring 及 SpringBoot 的很多注解都是基于后置处理器实现的。
参考
https://stackoverflow.com/questions/8519187/spring-postconstruct-vs-init-method-attribute
https://www.bilibili.com/video/BV1oW41167AV Spring 源码,讲解很流畅,值得一看
Spring 官方文档。其实本文中列举出的多种自定义初始化和销毁的方法或注解都有详尽的注释,平时要多注意阅读。
最后,水平有限,欢迎交流及指正。
版权声明: 本文为 InfoQ 作者【xiaoxi666】的原创文章。
原文链接:【http://xie.infoq.cn/article/c66df7f79e46553362981cdf6】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
xiaoxi666
一枚后端coder,一起来玩儿一起学! 2017.11.09 加入
博客园:http://www.cnblogs.com/xiaoxi666/ GitHub : https://github.com/xiaoxi666 微信公众号:xiaoxi666
评论 (3 条评论)