Spring IoC之Bean的生命周期

发布于 2019-11-26 | 更新于 2021-12-05

image-20191116162720255

如上图:

  1. 启动容器后,会对scope为singleton并且非懒加载的bean进行实例化(getBean方法触发实例化);
  2. 按照BeanDefinition定义信息配置信息,注入所有属性;
  3. 如果实现了BeanNameAware接口,会调用接口的setBeanName方法,传入该bean的唯一标识,以便获取该bean的唯一标识;
  4. 如果实现了BeanFactoryAware接口,会调用该接口的setBeanFactory方法,传入该bean的BeanFactory,以便获取bean的BeanFactory;
  5. 如果实现了ApplicationContextAware接口,会调用该接口的setApplicationContext方法,传入该bean的ApplicationContext,以便获取该Bean的ApplicationContext;
  6. 如果实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialization方法;
  7. 如果实现了InitializingBean接口,会调用该接口的afterPropertiesSet方法;
  8. 如果配置了init-method方法,则执行此方法;
  9. 如果实现了BeanPostProcessor接口,则会回调该接口的postProcessAfterInitialization方法;
  10. 这个时候,就可以正式使用该bean了,对于scope为singleton的bean,Spring的ioc容器中会缓存一份该bean的实例,而对于prototype的bean,每次调用都会new一个新的对象,该对象的生命周期交给调用方管理,不由Spring容器管理;
  11. 容器关闭的时候,如果bean实现了DisposableBean接口,则会回调该接口的destroy方法;
  12. 如果bean配置了destroy-method方法,会执行此方法。

Spring Bean的生命周期中,主要包含三个阶段:初始化阶段,使用阶段,销毁阶段。其中初始化阶段和销毁阶段主要通过以下回调方式进行介入调整:3个Aware接口,两类BeanPostProcessor(自定义BeanPostProcessor和基于注解的CommonAnnotationBeanPostProcessor),InitializingBeanDisposableBean,以及两个基于xml配置的方法(init-method, destroy-method)。如下图:

image-20191117200054987

注意:需要在xml文件中需要以下配置以便开启CommonAnnotationBeanPostProcessor支持:

context:annotation-config/

这个配置会自动注册以下的post-processor: AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, 还有前面提到的 RequiredAnnotationBeanPostProcessor

参考:2.9、基于注解的容器配置

@Autowired, @Inject, @Resource以及@Value注解是通过BeanPostProcessor实现的,所以你不可以在你自己的BeanPostProcessor或者BeanFactoryPostProcessor中使用这些注解,而应该通过XML或者@Bean注解来配置。

下面是一个bean生命周期的实例:

LifeCycleBean,使用以上生命周期中各个回调方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* Created by arthinking on 17/11/2019.
*/
public class LifeCycleBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

@Override
public void setBeanName(String name) {
System.out.println("==== 1.BeanNameAware.setBeanName: " + name);
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("==== 2.BeanFactoryAware.setBeanFactory: " + beanFactory);
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("==== 3.ApplicationContextAware.setApplicationContext: " + applicationContext);
}

// ==== 4.BeanPostProcessor.postProcessBeforeInitialization

/**
* 由CommonAnnotationBeanPostProcessor处理, 相当于xml中的init-method配置
*/
@PostConstruct
public void initBean() {
System.out.println("==== 5.CommonAnnotationBeanPostProcessor.postConstruct");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("==== 6.InitializingBean.afterPropertiesSet");
}

public void initMethod() {
System.out.println("==== 7.init-method");
}

// ==== 8.BeanPostProcessor.postProcessAfterInitialization

/**
* 由CommonAnnotationBeanPostProcessor处理, 相当于xml中的destroy-method配置
*/
@PreDestroy
public void destroyBean() {
System.out.println("==== 9.CommonAnnotationBeanPostProcessor.preDestroy");
}

@Override
public void destroy() throws Exception {
System.out.println("==== 10.DisposableBean.destroy");
}

public void destroyMethod() {
System.out.println("==== 11.destroy-method");
}

}

自定义BeanPostProcessor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Created by arthinking on 17/11/2019.
*/
@Service
public class BeanPostService implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LifeCycleBean) {
System.out.println("==== 4.BeanPostProcessor.postProcessBeforeInitialization: " + beanName);
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LifeCycleBean) {
System.out.println("==== 8.BeanPostProcessor.postProcessAfterInitialization: " + beanName);
}
return bean;
}

}

xml配置

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="lifeCycleBean" class="com.itzhai.spring.demo.beans.LifeCycleBean" init-method="initMethod" destroy-method="destroyMethod"/>
</beans>

输出结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2019-11-17 17:06:44.658  INFO 59661 --- [           main] .w.s.a.s.AnnotationActionEndpointMapping : Supporting [WS-Addressing August 2004, WS-Addressing 1.0]
==== 1.BeanNameAware.setBeanName: lifeCycleBean
==== 2.BeanFactoryAware.setBeanFactory: org.springframework.beans.factory.support.DefaultListableBeanFactory@76f4b65: ...
==== 3.ApplicationContextAware.setApplicationContext: org.springframework.web.context.support.GenericWebApplicationContext@e25951c, started on Sun Nov 17 17:06:42 CST 2019
==== 4.BeanPostProcessor.postProcessBeforeInitialization: lifeCycleBean
==== 5.CommonAnnotationBeanPostProcessor.postConstruct
==== 6.InitializingBean.afterPropertiesSet
==== 7.init-method
==== 8.BeanPostProcessor.postProcessAfterInitialization: lifeCycleBean
...
2019-11-17 17:06:49.385 INFO 59661 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
==== 9.CommonAnnotationBeanPostProcessor.preDestroy
==== 10.DisposableBean.destroy
==== 11.destroy-method

Process finished with exit code 0

References

Top 50 Spring Interview Questions You Must Prepare In 2019

Spring Context and Bean Lifecycle callbacks: practical examples of usage

[Spring 20面试题]([https://github.com/Homiss/Java-interview-questions/blob/master/框架/Spring 面试题.md](https://github.com/Homiss/Java-interview-questions/blob/master/框架/Spring 面试题.md))

本文作者: arthinking

本文链接: https://www.itzhai.com/articles/spring-ioc-bean-lifecycle.html

版权声明: 版权归作者所有,未经许可不得转载,侵权必究!联系作者请加公众号。

×
IT宅

关注公众号及时获取网站内容更新。