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

发布于: 13 小时前
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
*/
@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
容器销毁完毕

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

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

先看初始化

其中:

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

  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官方文档。其实本文中列举出的多种自定义初始化和销毁的方法或注解都有详尽的注释,平时要多注意阅读。

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

发布于: 13 小时前 阅读数: 47
用户头像

xiaoxi666

关注

翻岩卷浪,尽享激荡人生。 2017.11.09 加入

博客园:http://www.cnblogs.com/xiaoxi666/ GitHub : https://github.com/xiaoxi666

评论 (1 条评论)

发布
用户头像
感谢分享原创文章,InfoQ首页推荐了。
1 小时前
回复
谢谢鼓励~
刚刚
回复
没有更多了
Spring Bean生命周期——初始化和销毁