在Spring体系中,对象的实例(Bean)都是交给Spring容器进行管理的,但是对于Bean在Spring中是创建及销毁流程,很多人都只有一个模糊的概念,今天我们就来认真地探寻一下Bean生命周期的问题。
生命周期图
首先,给大家晒上一张我画的生命周期图,当然这并不是完整的流程,像 InstantiationAwareBeanPostProcessor
里面的 postProcessProperties()
在图上就没有体现,为啥不画呢?
因为目前大家基本上都使用SpringBoot在做项目开发,如果需要给Bean的属性注入某些值的话,基本都是由@Bean声明一个方法然后再给其设置上预期的值,这样的话,就不会经过上面的这个方法了。另外,BeanFactoryPostProcessor
这里也没有画,因为BeanFactoryPostProcessor
是处理BeanFactory
的,在getBean()
方法调用前已经执行过了,不在Bean的生命周期范围内。
整张图分为两个部分,横线以上是Bean的初始化流程,下面是Bean的销毁流程。
初始化流程
为方便记忆,我将初始化流程分为三条支线,当然,实际代码的逻辑层次上不是这么划分的:
- 第一条线(蓝色):创建Bean前后,包裹着
InstantiationAwareBeanPostProcessor
的postProcessBeforeInstantiation()
与postProcessAfterInstantiation()
方法,一前一后,根据方法名可以很好的区分。 - 第二条线(绿色):Aware相关钩子方法调用,以
BeanNameAware
、BeanFactoryAware
、ApplicationContextAware
依次组成,具体调用的方法名可以使用类名推断出来。(这里我没有画BeanClassLoaderAware
,因为个人认为使用不多,它位于BeanNameAware
、BeanFactoryAware
之间) - 第三条线(黄色):由
BeanPostProcessor
包裹头尾,中间部分由@PostConstruct
、InitializingBean.afterPropertiesSet()
、init-method
三个节点依次组成。
销毁流程
销毁流程比较简单,由@PreDestroy
、DisposableBean.destroy()
、destroy-method
三个部分组成,细心的同学会发现它与初始化的第三条线是一一对应的,也就是记住了初始化流程中的第三条线,销毁流程也就记住了。
对应映射关系整理如下:
初始化 | 销毁 |
---|---|
@PostConstruct | @PreDestroy |
InitializingBean | DisposableBean |
init-method | destroy-method |
实验论证
为了印证上面的内容,我准备了一个实验,通过该实验可能观察到Bean创建及销毁的整个流程。
首先,使用 https://start.spring.io 创建一个最简单的SpringBoot工程(版本号:2.1.8),然后在创建一个自定义的Bean对象LifecycleBean
实现BeanFactoryAware
, ApplicationContextAware
,InitializingBean
, DisposableBean
等接口。
public class LifecycleBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware,
InitializingBean, DisposableBean {
public LifecycleBean() {
Printer.print("new Bean()");
}
@Override
public void setBeanName(String s) {
Printer.print("BeanNameAware.setBeanName()");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Printer.print("BeanFactoryAware.setBeanFactory()");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Printer.print("ApplicationContextAware.setApplicationContext()");
}
@Override
public void afterPropertiesSet() throws Exception {
Printer.print("InitializingBean.afterPropertiesSet()");
}
@Override
public void destroy() throws Exception {
Printer.print("DisposableBean.destroy()");
}
public void initMethod() {
Printer.print("init-method");
}
public void destroyMethod() {
Printer.print("destroy-method");
}
@PostConstruct
public void postConstruct() {
Printer.print("@PostConstruct");
}
@PreDestroy
public void preDestory() {
Printer.print("@PreDestroy");
}
}
另外,为了将LifecycleBean
委托给Spring的容器管理,定义一个LifecycleConfiguration
配置类,并在其中指定LifecycleBean
的init-method
与destroy-method
方法。
@Configuration
public class LifecycleConfiguration {
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public LifecycleBean lifecycleBean() {
return new LifecycleBean();
}
}
然后,再定义一个LifecycleInstantiationBeanPostProcessor
用于验证InstantiationAwareBeanPostProcessor
的执行节点。
@Component
public class LifecycleInstantiationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass == LifecycleBean.class) {
Printer.print("InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (bean instanceof LifecycleBean) {
Printer.print("InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()");
}
return false;
}
}
最后,再为BeanPostProcessor
定义一个实现类LifecycleBeanPostProcessor
。
@Component
public class LifecycleBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LifecycleBean) {
Printer.print("BeanPostProcessor.postProcessBeforeInitialization()");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LifecycleBean) {
Printer.print("BeanPostProcessor.postProcessAfterInitialization()");
}
return bean;
}
}
在上述代码实现中,输入借用了一个自定义的工具类Printer
,其作用给流程节点加上编号,让流程更加直观,这里,我也贴一下它的简单实现:
public class Printer {
private static AtomicInteger lineNumber = new AtomicInteger(0);
public static void print(String value) {
System.out.println(lineNumber.addAndGet(1) + " : " + value);
}
}
实现案例准备完毕后,运行一下应用,得出输出内容如下:
1 : InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
2 : new Bean()
3 : InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
4 : BeanNameAware.setBeanName()
5 : BeanFactoryAware.setBeanFactory()
6 : ApplicationContextAware.setApplicationContext()
7 : BeanPostProcessor.postProcessBeforeInitialization()
8 : @PostConstruct
9 : InitializingBean.afterPropertiesSet()
10 : init-method
11 : BeanPostProcessor.postProcessAfterInitialization()
2019-10-01 18:35:58.935 INFO 1192 — [main] SpringApplication : Started SpringApplication in 1.783 seconds
12 : @PreDestroy
13 : DisposableBean.destroy()
14 : destroy-method
从输出内容来看,中间有一段应用启动完成的日志,将Bean创建流程与销毁流程完全划分开,而创建和销毁的输出内容我们上图表述的一致,故流程得证。
迎您扫一扫上面的微信公众号,订阅我的博客!