写点什么

Spring Bean 生命周期——初始化和销毁

用户头像
xiaoxi666
关注
发布于: 2020 年 05 月 29 日
Spring Bean生命周期——初始化和销毁

在 Spring Bean 的生命周期中,有两个核心环节,那就是初始化和销毁,下面我们看看都有哪几种方式指定对应的初始化或销毁操作,以及它们的作用原理。

多种方式概览

  • 在 @Bean 注解中指定参数:

  1. initMethod:自定义初始化逻辑(如果用 xml 文件指定,就是 init-method 参数)

  2. destroyMethod:自定义销毁逻辑(如果用 xml 文件指定,就是 destroy-method 参数)

  • 实现 InitializingBean 和 DisposableBean 接口:

  1. 实现 InitializingBean 接口的 afterPropertiesSet 方法:自定义初始化逻辑

  2. 实现 DisposableBean 接口的 destroy 方法:自定义销毁逻辑

  • 利用 JSR250 规范中的注解(注意这两个注解都是 javax 包中的,而非 Spring 自带):

  1. @PostConstruct:自定义初始化逻辑

  2. @PreDestroy:自定义销毁逻辑

  • 自定义后置处理器:

  1. 实现 postProcessBeforeInitialization 方法:自定义初始化逻辑

  2. 实现 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 */@Configurationpublic class MyConfiguration {
@Bean(initMethod = "myInitMethod", destroyMethod = "myDestroyMethod") public MyBeanWithInitMethodAndDestroyMethod myBeanWithInitMethodAndDestroyMethod() { return new bean.MyBeanWithInitMethodAndDestroyMethod(); }}
复制代码


执行测试类,输出:

MyBeanWithInitMethodAndDestroyMethod: constructorMyBeanWithInitMethodAndDestroyMethod: @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 */@Configurationpublic class MyConfiguration {
@Bean public MyBeanImplementsInitializingBeanAndDisposableBean myBeanImplementsInitializingBean() { return new bean.MyBeanImplementsInitializingBeanAndDisposableBean(); }}
复制代码


执行测试类,输出:

MyBeanImplementsInitializingBeanAndDisposableBean: constructorMyBeanImplementsInitializingBeanAndDisposableBean: 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 */@Configurationpublic class MyConfiguration {
@Bean public MyBeanWithPostConstructAndPreDestroy myBeanWithPostConstructAndPreDestroy() { return new MyBeanWithPostConstructAndPreDestroy(); }}
复制代码


执行测试类,输出:

MyBeanWithPostConstructAndPreDestroy: constructorMyBeanWithPostConstructAndPreDestroy: @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 */
@Componentpublic 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")@Configurationpublic class MyConfiguration { //这里我们并没有配置bean,先观察一下后置处理器会干什么}
复制代码


执行测试类,输出:

MyBeanPostProcessor: constructorMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: 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")@Configurationpublic class MyConfiguration { @Bean(initMethod = "myInitMethod", destroyMethod = "myDestroyMethod") public MyBeanWithInitMethodAndDestroyMethod myBeanWithInitMethodAndDestroyMethod() { return new MyBeanWithInitMethodAndDestroyMethod(); }}
复制代码


输出:

MyBeanPostProcessor: constructorMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanWithInitMethodAndDestroyMethod: constructorMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanWithInitMethodAndDestroyMethod: @Bean#initMethodMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization容器创建完毕=============================MyBeanWithInitMethodAndDestroyMethod: @Bean#destroyMethod容器销毁完毕
复制代码


可以看到,后置处理器会在我们的初始化方法执行前后分别调用。


其他类型的 Bean 同理,这里贴一下输出:

MyBeanPostProcessor: constructorMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanImplementsInitializingBeanAndDisposableBean: constructorMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanImplementsInitializingBeanAndDisposableBean: InitializingBean#afterPropertiesSetMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization容器创建完毕=============================MyBeanImplementsInitializingBeanAndDisposableBean: DisposableBean#destroy容器销毁完毕
复制代码


MyBeanPostProcessor: constructorMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanWithPostConstructAndPreDestroy: constructorMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanWithPostConstructAndPreDestroy: @PostConstructMyBeanPostProcessor: 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")@Configurationpublic class MyConfiguration {
@Bean(initMethod = "myInitMethod", destroyMethod = "myDestroyMethod") public MyBeanWithManyMethod myBeanWithManyMethod() { return new MyBeanWithManyMethod(); }}
复制代码


输出:

MyBeanPostProcessor: constructorMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitializationMyBeanWithManyMethod: constructorMyBeanPostProcessor: BeanPostProcessor#postProcessBeforeInitializationMyBeanWithManyMethod: @PostConstructMyBeanWithManyMethod: InitializingBean#afterPropertiesSetMyBeanWithManyMethod: @Bean#initMethodMyBeanPostProcessor: BeanPostProcessor#postProcessAfterInitialization容器创建完毕=============================MyBeanWithManyMethod: @PreDestroyMyBeanWithManyMethod: DisposableBean#destroyMyBeanWithManyMethod: @Bean#destroyMethod容器销毁完毕
复制代码


可以看到三种方式的顺序如图所示:


那么这个顺序是在哪里决定的呢?来看看源码:

先看初始化



其中:

  • 第一步和第三步中的后置处理器包括两个东东。

  1. 我们自定义的后置处理器

  2. @PostConstruct 和 @PreDestroy 两个注解也使用后置处理器,只不过它们使用的是 Spring 自带的后置处理器,也即 CommonAnnotationBeanPostProcessor,它在 Spring 容器初始化时就被注册进来了。

  • 第二步中的自定义初始化方法也包括两个东东。

  1. InitializingBean#afterPropertiesSet

  2. @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 ## 测试类
复制代码


扩展

  1. 多种初始化方式发生的时机不同,但实现的效果类似。

  2. 最好不要将多种方式混用,尽量保持代码的简单性。

  3. 我们最常用的方式是在创建 bean 时就指定 initMethod 和 destroyMethod。

  4. @PostConstruct 和 @PreDestroy 注解来源于 Javax 包,而非 Spring 自带。

  5. 后置处理器的功能最为强大,Spring 及 SpringBoot 的很多注解都是基于后置处理器实现的。

参考


  1. https://stackoverflow.com/questions/8519187/spring-postconstruct-vs-init-method-attribute

  2. https://www.bilibili.com/video/BV1oW41167AV Spring 源码,讲解很流畅,值得一看

  3. Spring 官方文档。其实本文中列举出的多种自定义初始化和销毁的方法或注解都有详尽的注释,平时要多注意阅读。


最后,水平有限,欢迎交流及指正。

发布于: 2020 年 05 月 29 日阅读数: 1322
用户头像

xiaoxi666

关注

一枚后端coder,一起来玩儿一起学! 2017.11.09 加入

博客园:http://www.cnblogs.com/xiaoxi666/ GitHub : https://github.com/xiaoxi666 微信公众号:xiaoxi666

评论 (3 条评论)

发布
用户头像
写的很优秀,榜样,哈哈
2020 年 08 月 05 日 16:27
回复
用户头像
感谢分享原创文章,InfoQ首页推荐了。
2020 年 05 月 30 日 09:45
回复
谢谢鼓励~
2020 年 05 月 30 日 10:53
回复
没有更多了
Spring Bean生命周期——初始化和销毁