一、前言

所谓Spring Bean的生命周期指的是Bean从创建到初始化再到销毁的过程,这个过程由IOC容器管理。一个完整的Bean生命周期可以参考Spring Bean生命周期。这里我们主要记录一些和Bean生命周期相关的细节。

二、Bean的初始化和销毁

在整个生命周期过程中,我们可以自定义Bean的初始化和销毁钩子函数,当Bean的生命周期到达相应的阶段的时候,Spring会调用我们自定义的Bean的初始化和销毁方法。自定义Bean初始化和销毁方法有多种方式,下面逐一介绍。

2.1 @Bean

上一节中介绍了可以在配置类中通过@Bean注解来注册Bean,我们也可以通过它来指定Bean的初始化和方法。

为了演示,我们新建一个Spring Boot项目,然后创建一个User类:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class User {
public User(){
System.out.println("User 无参构造函数");
}

public void init(){
System.out.println("初始化User");
}

public void destory(){
System.out.println("销毁User");
}
}

然后在配置类里注册该组件,并指定初始化和销毁方法:

1
2
3
4
5
6
7
8
@Configuration
public class WebConfig {

@Bean(initMethod = "init", destroyMethod = "destory")
public User user() {
return new User();
}
}

其中initMethod = "init"和destroyMethod = "destory"与User类里的init,destory方法相对应。

在Spring Boot测试类中增加测试:

1
2
3
4
5
6
7
8
9
10
11
12
@RunWith(SpringRunner.class)
@SpringBootTest
public class BeanLifeCycleApplicationTests {
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);
System.out.println("容器创建完毕");
User user = context.getBean(User.class);
// 关闭 IOC 容器
context.close();
}
}

启动测试类,观察控制台输出:

User 无参构造函数
初始化User
容器创建完毕
销毁User

从上面的输出我们看出在容器启动之前,先调用对象的无参构造器创建对象,然后调用初始化方法,在容器关闭的时候调用销毁方法。

上面的情况是对于单例而言的,如果组件是多例模式又是什么情况呢?我们把上面的组件注册配置改为多例,然后再次启动项目,观察控制台输出:

User 无参构造函数
初始化User
容器创建完毕
销毁User

控制台的输出和我们上节讨论的一致,即在多例模式下,IOC容器启动的时候并不会去创建对象,而是在每次获取的时候才会去调用方法创建对象,创建完对象后再调用初始化方法。但在容器关闭后,Spring并没有调用相应的销毁方法,这是因为在多例模式下,容器不会管理这个组件(只负责在你需要的时候创建这个组件),所以容器在关闭的时候并不会调用相应的销毁方法。

2.2 nitializingBean&DisposableBean

除了上面这种方式指定初始化和销毁方法外,Spring还为我们提供了和初始化,销毁相对应的接口:
1.InitializingBean接口包含一个afterPropertiesSet方法,我们可以通过实现该接口,然后在这个方法中编写初始化逻辑。
2.DisposableBean接口包含一个destory方法,我们可以通过实现该接口,然后再这个方法中编写销毁逻辑。

新建一个类,名称为Dept,然后实现这两个接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Dept implements InitializingBean, DisposableBean {

public Dept(){
System.out.println("Dept 无参构造函数");
}

@Override
public void destroy() throws Exception {
System.out.println("销毁Dept");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化Dept");
}
}

在配置类中注册这个组件:

1
2
3
4
   @Bean
public Dept dept(){
return new Dept();
}

测试一波:

1
2
3
4
5
6
7
8
9
10
11
@RunWith(SpringRunner.class)
@SpringBootTest
public class BeanLifeCycleApplicationTests {
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);
System.out.println("容器创建完毕");
// 关闭 IOC 容器
context.close();
}
}

启动测试类,观察控制台输出:

Dept 无参构造函数
初始化Dept
容器创建完毕
销毁Dept

2.3 @PostConstruct&@PreDestroy

除了上面两种指定初始化和销毁方法的方式外,我们还可以使用@PostConstruct和@PreDestroy注解修饰方法来指定相应的初始化和销毁方法。

新建一个类,名称为Menu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Menu {

public Menu(){
System.out.println("Menu 无参构造函数");
}

@PostConstruct
public void init() {
System.out.println("初始化Menu");
}

@PreDestroy
public void destory() {
System.out.println("销毁Menu");
}
}

在配置类中注册这个组件:

1
2
3
4
    @Bean
public Menu menu(){
return new Menu();
}

测试一波:

1
2
3
4
5
6
7
8
9
10
11
@RunWith(SpringRunner.class)
@SpringBootTest
public class BeanLifeCycleApplicationTests {
@Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);
System.out.println("容器创建完毕");
// 关闭 IOC 容器
context.close();
}
}

启动测试类,观察控制台输出:

Menu 无参构造函数
初始化Menu
容器创建完毕
销毁Menu

效果和上面两种方式一致。
注意:这两个注解并非Spring提供,而是JSR250规范提供。

三、BeanPostProcessor

Spring提供了一个BeanPostProcessor接口,俗称Bean后置通知处理器,它提供了两个方法postProcessBeforeInitialization和postProcessAfterInitialization。其中postProcessBeforeInitialization在组件的初始化方法调用之前执行,postProcessAfterInitialization在组件的初始化方法调用之后执行。它们都包含两个入参:
1.bean:当前组件对象;
2.beanName:当前组件在容器中的名称。

两个方法都返回一个Object类型,我们可以直接返回当前组件对象,或者包装后返回。

我们来定义一个BeanPostProcessor接口的实现类MyBeanPostProcessor:

1
2
3
4
5
6
7
8
9
10
11
12
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + " 初始化之前调用");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + " 初始化之后调用");
return bean;
}
}

在配置类中注册该组件:

1
2
3
4
@Bean
public MyBeanPostProcessor myBeanPostProcessor () {
return new MyBeanPostProcessor();
}

再次启动测试类,观察控制台输出:

beanLifeCycleApplication 初始化之前调用
beanLifeCycleApplication 初始化之后调用
User 无参构造函数
user 初始化之前调用
初始化User
user 初始化之后调用
Dept 无参构造函数
dept 初始化之前调用
初始化Dept
dept 初始化之后调用
Menu 无参构造函数
menu 初始化之前调用
初始化Menu
menu 初始化之后调用
org.springframework.boot.autoconfigure.AutoConfigurationPackages 初始化之前调用
org.springframework.boot.autoconfigure.AutoConfigurationPackages 初始化之后调用
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration 初始化之后调用
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration 初始化之后调用
objectNamingStrategy 初始化之前调用
objectNamingStrategy 初始化之后调用
mbeanServer 初始化之前调用
mbeanServer 初始化之后调用
mbeanExporter 初始化之前调用
mbeanExporter 初始化之后调用
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration 初始化之后调用
springApplicationAdminRegistrar 初始化之前调用
springApplicationAdminRegistrar 初始化之后调用
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration 初始化之后调用
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration 初始化之后调用
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration 初始化之后调用
applicationAvailability 初始化之前调用
applicationAvailability 初始化之后调用
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration 初始化之后调用
org.springframework.boot.context.properties.BoundConfigurationProperties 初始化之前调用
org.springframework.boot.context.properties.BoundConfigurationProperties 初始化之后调用
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata 初始化之前调用
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata 初始化之后调用
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration 初始化之后调用
spring.lifecycle-org.springframework.boot.autoconfigure.context.LifecycleProperties 初始化之前调用
spring.lifecycle-org.springframework.boot.autoconfigure.context.LifecycleProperties 初始化之后调用
lifecycleProcessor 初始化之前调用
lifecycleProcessor 初始化之后调用
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties 初始化之前调用
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties 初始化之后调用
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration 初始化之后调用
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration 初始化之后调用
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties 初始化之前调用
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties 初始化之后调用
taskExecutorBuilder 初始化之前调用
taskExecutorBuilder 初始化之后调用
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration 初始化之前调用
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration 初始化之后调用
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties 初始化之前调用
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties 初始化之后调用
taskSchedulerBuilder 初始化之前调用
taskSchedulerBuilder 初始化之后调用
spring.devtools-org.springframework.boot.devtools.autoconfigure.DevToolsProperties 初始化之前调用
spring.devtools-org.springframework.boot.devtools.autoconfigure.DevToolsProperties 初始化之后调用
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$RestartConfiguration 初始化之前调用
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$RestartConfiguration 初始化之后调用
fileSystemWatcherFactory 初始化之前调用
fileSystemWatcherFactory 初始化之后调用
restartingClassPathChangedEventListener 初始化之前调用
restartingClassPathChangedEventListener 初始化之后调用
classPathRestartStrategy 初始化之前调用
classPathRestartStrategy 初始化之后调用
classPathFileSystemWatcher 初始化之前调用
classPathFileSystemWatcher 初始化之后调用
conditionEvaluationDeltaLoggingListener 初始化之前调用
conditionEvaluationDeltaLoggingListener 初始化之后调用
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LiveReloadConfiguration 初始化之前调用
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LiveReloadConfiguration 初始化之后调用
liveReloadServer 初始化之前调用
liveReloadServer 初始化之后调用
optionalLiveReloadServer 初始化之前调用
2020-08-26 22:13:59.703 INFO 17012 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
optionalLiveReloadServer 初始化之后调用
liveReloadServerEventListener 初始化之前调用
liveReloadServerEventListener 初始化之后调用
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration 初始化之前调用
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration 初始化之后调用
2020-08-26 22:13:59.729 INFO 17012 --- [ restartedMain] c.wno704.boot.BeanLifeCycleApplication : Started BeanLifeCycleApplication in 0.686 seconds (JVM running for 2.332)
销毁Menu
销毁Dept
销毁User

可以看到,BeanPostProcessor对IOC容器中所有组件都生效。