之前十一假期,基于SpringBoot实现集成公司业务和通用封装的starter,有点类似支付宝的Sofa-Boot。在实现过程中,不断优化的过程发现对源码理解不好,starter很容易写的不那么“聪明”。所以就趁着假期一点点跟着源码阅读了起来,今天来分享一篇总结简单Bean的生命周期。
我的技术学习方法
我阅读源码的过程中,通常分两步走:跳出来,看全景;钻进去,看本质。先了解Bean的生命周期图对其有大体了解,该技术在大脑中有了一个“简单”的构图后。再阅读相关源码去确认自己在看全景时的大脑构图是否合理。这个过程其实也适用于面对新环境,先熟悉自己所处项目的业务,再过技术栈与代码相关细节。钻进去看本质的过程往往是“煎熬的”,需要坚持与不断的思考。
Bean的生命周期图

Bean创建过程的源码阅读索引
Spring源码版本: 5.0.9.RELEASE
源码阅读索引
DefaultListableBeanFactory
| preInstantiateSingletons(726) --> getBean(759);
AbstractBeanFactory
| getBean(198) --> doGetBean(199)
| doGetBean(239) --> getSingleton(315)
DefaultSingletonBeanRegistry
| getSingleton(202) --> singletonFactory.getObject(222)
| getSingleton(315) --> createBean(317)
AbstractAutowireCapableBeanFactory
| createBean(456) --> doCreateBean(495)
| doCreateBean(526) --> createBeanInstance(535) return BeanWrapper
| doCreateBean(526) --> addSingletonFactory(566) 加入到三级缓存SingletonFactories
| doCreateBean(526) --> populateBean(572)
| doCreateBean(526) --> initializeBean(573)
| initializeBean(1678) --> invokeAwareMethods(1686)
| invokeAwareMethods(1709) --> ((BeanNameAware) bean).setBeanName(1712)
| invokeAwareMethods(1709) --> ((BeanClassLoaderAware) bean).setBeanClassLoader(1717)
| invokeAwareMethods(1709) --> ((BeanFactoryAware) bean).setBeanFactory(1721)
| initializeBean(1678) --> applyBeanPostProcessorsBeforeInitialization(1691) 这里面通常调用的是AwareProcessor
| initializeBean(1678) --> invokeInitMethods(1695)
| invokeInitMethods(1695) --> ((InitializingBean) bean).afterPropertiesSet(1758)
| invokeInitMethods(1695) --> invokeCustomInitMethod(1767)
| initializeBean(1678) --> applyBeanPostProcessorsAfterInitialization(1703)
上面三个类之间的关系

上面的类继承图是我简化过的,其实真正的Spring的BeanFacotory类泛化体系远比此复杂多。
Bean的创建过程源码分析
示例代码
@Slf4j
@Component
public class ComponentA implements InitializingBean, DisposableBean, BeanFactoryAware, ApplicationContextAware {
@Autowired
private ComponentB componentB;
@Value("${ca.test.val:default}")
private String valA;
@Override
public void destroy() {
log.info("$destroy()...");
}
@Override
public void afterPropertiesSet() {
log.info("$afterPropertiesSet()...");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("$setApplicationContext() applicationContext:{}", applicationContext);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.info("$setBeanFactory() beanFactory:{}", beanFactory);
}
}
@Component
public class ComponentB {
@Autowired
private ComponentA componentA;
}
@SpringBootApplication
public class EasyUcApplication {
public static void main(String[] args) {
/**
* 使用SpringBoot-2.0.5.RELEASE去启动Spring容器,对应就是需要的Spring-5.0.9.RELEASE。
*/
SpringApplication.run(EasyUcApplication.class, args);
}
}
开始源码阅读
- 按照源码阅读索引的入口,我们查看下源码

因为这块是循环遍历所有
BeanDefinitionNames,F9找到上面我们想要看到初始化过程的Bean。下文提到的所有F7、F8、F9分别代表进入方法内部、跳到下一行、跳到下一个断点处。
-
F8按照索引目录跟到759行
-
F7进入此方法,进入到抽象类AbstractBeanFactory
-
F7进入doGetBean方法 进入到这个方法后,看下246行,它最终会进入到
DefaultSigletonBeanRegistry中的getSingleton 到这先认识下这三个缓存
Map:- singletonObjects: singleton object cache
- earlySingletonObjects: Cache of singleton objects exposed in advance
- singletonFactories: singleton object factory cache
这三级缓存具体作用我们在
populate阶段再分析 -
返回到
AbstractBeanFactory的doGetBean(246),F8接着跟到315行 第二个参数是个函数式接口

-
F7跟进去,我们看到到第222行调用了getObject()
-
getObject()F7跟进去其实调用的就是createBean
-
F7跟进去,到了AbstractAutowireCapableBeanFacotory的createBean(456), 在这个方法内找到495行,F7进入此方法 接下来才开始正式进入到创建Bean的过程
创建Bean对象,加入第三级缓存中
- 上一步我们进入
AbstractAutowireCapableBeanFacotory的doCreateBean(526)行,F8一直到535行,F7进入此方法。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
/*省略代码*/
// 调用有Autowire的构造方式: 就是说构造方法的成员变量是需要注入值的。
Class<?> beanClass = resolveBeanClass(mbd, beanName);
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 简单的无参构造器:我们这里会走到这种方式
return instantiateBean(beanName, mbd); //1128
}
- 接着
F7进入到上面的instantiateBean(1128)
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
/*省略代码*/
// 1.实例化对象
Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
// 2.创建该对象的BeanWrapper
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
-
上面出现个BeanWrapper,它的作用是干什么的呢?
- 我们实例化对象的时候,其实是调用构造器去反射创建对象。
- 当我们想对其属性值赋值的时候,就可以使用
setPropertyValue去进行赋值,BeanWrapper提供一种可以直接对属性赋值的能力。如下面所示:
Class<?> clazz = Class.forName("cn.coderjia.easyuc.component.ComponentA");
Constructor<?> ctor = clazz.getDeclaredConstructor();
Object bean = ctor.newInstance();
BeanWrapper beanWrapper = new BeanWrapperImpl(bean);
beanWrapper.setPropertyValue("valA", "val");
- 我们一直
F8返回AbstractAutowireCapableBeanFacotory的doCreateBean(535), 然后F8到559行。
- 接着
F8跟到566行
F7进入此方法,到了DefaultSingletonBeanRegistry
我们可以发现这步是将对象创建的工厂函数缓存到
singletonFactories,目的为了解决循环引用的问题,那么什么是循环引用的情况与如何解决的呢?且看下文分解。
注入Bean的属性
- 上小节我们提出了疑问什么是循环引用?我们先来看一张图。
正如我们的示例代码,
ComponetA依赖ComponentB,ComponentB又依赖于ComponentA,Spring中Bean的实例化Bean对象后,会对属性值注入(populate),这样就会出现如上图的循环调用过程(instantiate A->populate ComponentB->instantiateB->populate ComponentA->instantiate A)。 - 上面我们分析了什么是循环引用,接下来我们先接着跟源码。
我们上回书说到,将实例化后未初始化的
Bean对象工厂放置到第三级缓存中。 F7进入到getEarlyBeanReference(566) 理论上讲,两级缓存就够了,对象实例化后放到
earlySingletonObjects缓存中,在需要提前引用的地方取出就可以解决循环引用的问题。但是第三级缓存存在的意义除了保存Bean外,还可以在获取的时候,对Bean可以做前置处理(InstantiationAwareBeanPostProcessor),有这样一种拓展的能力。 简单的理解就如上面图中的过程: 创建
Component A后,把Component A缓存起来,注入Component B属性时,创建Component B,Component B需要注入Component A,从缓存把Component A取出来,完成Component B的创建全过程,在将Component B返回给Component A,Component A也可完成创建全过程。F8跟到populateBean(572) 按照我们上面的解释,这步是会去注入
Componet B,然后自然而然需要创建Componet B。接下来看下是不是这样。F7进入此方法,到了AbstractAutowireCapableBeanFactory的populateBean(1277)行
F8一直往下跟1339行打个断点,然后一直F9跳到bp为AutowiredAnnotationBeanPostProcessor时候停止,F8跟到 1341行
F7进入此方法,来到CommonAnnotationBeanPostProcessor的metadata.inject(318)行
F7进入此方法,来到InjectionMetadata的inject(81) 写到这我们发现需要注入的属性
componetB和valA已经在checkoutedElements中,要对其进行值的注入。可以发现@Autowired和@Value值就是在这阶段对其赋值的。那么componetB和valA什么时候加到checkoutedElements中的呢?- 先回退下,找到
AbstractAutowireCapableBeanFactory的applyMergedBeanDefinitionPostPorcessors(547)行,打个断点
- 重新启动容器,
F9一直跳到ComponetA
F7跟进,进入到AbstractAutowireCapableBeanFactory的applyMergedBeanDefinitionPostPorcessors(1009)行
1011行打个断点,然后F9一直跳到bp为AutowiredAnnotationBeanPostProcessor
F7进入AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition(231)行
F8跟到232行,F7进入此方法,来到了AutowiredAnnotationBeanPostProcessor的findAutowiringMetadata(405)行
F8跟到AutowiredAnnotationBeanPostProcessor的buildAutowiringMetadata(417)行
F7进入此方法,来到了AutowiredAnnotationBeanPostProcessor的buildAutowiringMetadata(425)行,然后在433行打个断点
F9一直跳到ComponetB或者valA
F7进入此方法,来到了AutowiredAnnotationBeanPostProcessor的findAutowiredAnnotation(480)行 跟到这我们明白了,获取到当前对象的所有
field,然后找看看有没有我们“感兴趣”的field,“感兴趣”的注解是提前定义好的,放在autowiredAnnotationTypes中。autowiredAnnotationTypes中都有哪些注解,我们找到AutowiredAnnotationBeanPostProcessor的构造方法。 我们可以看到“感兴趣”的注解有
@Autowired、@Value、@Inject,所以ComponetB或者valA会最终被放置到checkedElements中。- 接下来我们回到
InjectionMetadata的inject(81),接着分析注入的过程 通过上面分析我们知道elementsToIterate一共有两个属性需要注入,分别是
ComponetB或者valA F7进入InjectionMetadata的inject(90)行,来到AutowiredAnnotationBeanPostProcessor的inject(570)行
F8跟到583行,F7进入beanFactory.resolveDependency(583)行,来到了DefaultListableBeanFacotory的doResolveDependency(1062)行
F7进入doResolveDependency(1062),来到DefaultListableBeanFacotory的1069行,接着在1135行打个断点,F9跳到此位置 我们知道当前需要注入的一个属性是ComponetB是个类,所以会走这进行初始化
F7进入descriptor.resolveCandidate(1135)行,来到DependencyDescriptor的resolveCandidate(248)行
F7进入beanFactory.getBean(251)行,一直跟到AbstractBeanFacotory的doGetBean(239)行,以下过程都是创建Componet B的过程,所以聚集在一起,等Componet B中需要注入Component A时我们在分开。
到246行,其实就是到了上面循环依赖解决方案图中第4步先从cache取出B的实例,显然没有那么就接着按图中走,第5步没有B的示例去instantiate个示例。
然后在317行打个断点,
F9跳到这
F7进入,F8跟到doCreateBean(495)行
F7进入,F8跟到doCreateBean(572)行 我们现在应该很清楚的知道,我们到了解决循环依赖问题的第7步骤
populate ComponentA,F7进入populateBean方法。populate ComponentA时,肯定最终会去试图创建ComponentA,也会回到AbstractBeanFacotry的doGetBean(239)行
F7进入getSingleton(246)行,一直跟到DefaultSingletonBeanRegistry的getSingleton(176)行,F8跟到185行 我们到了解决循环依赖问题的第8步骤,从
cache中取出Bean,而且这个Bean正好是我们上文书所说的那样,是实例化后的,未完成属性注入和初始化的。F8到最后doGetBean(392)行
- 接下来就是一直
F8跟到AutowiredAnnotationBeanPostProcessor的inject(611)行 这个时候就可以发现,
ComponetB创建完成,注入的是预先缓存好的示例化的ComponetA - 接下仍然一直
F8跟回到AbstractAutowireCapableBeanFacotry的doCreateBean(573)行 到这可以知道,
ComponetB对于ComponetA已经注入完成,573行是执行ComponetB初始化操作,我们主要看ComponetA的生命周期,所以可以直接F9跳过后面过程回到ComponetA的populateBean F9跳回到ComponetA的populateBean 至此
Component A彻底完成初始化和属性注入的过程,而且控制台没有任何输出也符合我们生命周期图的预测。
初始化方法的前置处理
F7进入AbstractAutowireCapableBeanFacotry的doCreateBean(573)行来到initializeBean(1678)行
F7进入invokeAwareMethods(1686)行 我们的示例代码
ComponetA implements BeanFactoryAware, 所以这块会回调setBeanFactoryF8执行完invokeAwareMethods 符合我们生命周期图的预期,打印了
$setBeanFactory()...F8跳回到initializeBean(1691)行
F7跟进去,到了AbstractAutowireCapableBeanFacotry的applyBeanPostProcessorsBeforeInitialization(411)行 跟到416行时候可以发现两个事情,第一个是这里面通常执行的是
*AwareProcessor且是在invokeAwareMethods后面执行的,符合我们生命周期图,第二个是ApplicationContextAwareProcessor是默认给我们所有bean都创建的*AwareProcessor,我们来看下这个ApplicationContextAwareProcessor是干什么的。F7进入applyBeanPostProcessorsBeforeInitialization(416)行,来到了ApplicationContextAwareProcessor的postProcessBeforeInitialization(79)行,F8一直跟到invokeAwareInterfaces(96)行
F7进入invokeAwareInterfaces(96)行,来到了invokeAwareInterfaces(102)行 原来还会帮我们默认加
ApplicationContextAwareProcessor,如果我们实现了这些接口,它就会回调。我们的示例代码中ComponentA implements ApplicationContextAware,所以应该会执行ComponentA的setApplicationContextF8跟到invokeAwareInterfaces(102)这个方法的最后,看下打印结果。 符合我们直接执行的
*Aware接口,生命周期要早于*AwareProcessor。
所有属性注入结束
AbstractAutowireCapableBeanFacotry的initializeBean(1678)中的invokeInitMethods(1695)行,F7进入此方法,再F8跟到invokeInitMethods(1758)行
F8执行afterPropertiesSet,因为ComponentA implements InitializingBean,所以控制台肯定会打印$afterPropertiesSet()...,如下图所示:
开始init
F8下面的1767行就是执行,目标init方法
创建结束
F8跟回到AbstractAutowireCapableBeanFacotry的applyBeanPostProcessorsAfterInitialization(1703)行 这个过程就是调用初始化的后置处理器和前置处理器过程类似。
F8跟到AbstractAutowireCaplableBeanFacotry的doCreateBean(614)行
Bean注册为DisposableBean会随着容器销毁而销毁。F8一直跟回到DefaultSingletonBeanRegistry的getSingleton(248)行
F7进入到此方法,看看创建Bean的最后一步 将bean从二级缓存
earlySingletonObjects转存到以及缓存singletonObjects,以上过程我们完成了Bean的整个创建过程,Spirng之所以处理的这么“松散”(低耦合),其实就是在Bean整个生命周期过程中,提供给用户更好的拓展能力。结合自己的业务场景,灵活定制。
Bean的销毁过程源码分析
- 先来了解下
Runtime.getRuntime().addShutdownHook(Thread hook),写段测试代码。 运行结果:
当main方法执行结束,相当于
System.exit(0)退出,就会回调是添加的Hook Thread,Spring也是这样做的。 - 理解
Spring的钩子线程,找到SpringApplication的run(333)行,进入refreshContext(333)行,来到SpringApplication的415行,F7进入此方法,来到AbstractApplicationContext的registerShutdownHook(930)行 这段代码与我们的示例代码类似,这个
钩子当系统退出时调用doClose()方法,这段小内容还要碎碎念个事儿,SpringBoot我们知道他帮我们自动装配了很多配置,其实本质是在spring.factories定义好需要自动装配的类,把定义好的类包装成Spring需要的BeanDefinition,剩下的事儿就交给Spring就好了。当然SpringBoot还有自己完整的事件发布体系(观察者模式),让整个SpringBoot的代码结构看起来非常清晰。这些话虽然有些跑题,但是这就是我为什么搞SpringBoot starter却进入了Spring的世界。
- 一个不得不说的点
不知道你有没有想过一个问题,上面的main方法为什么执行完不退出。我相信你看完这篇文章(JVM退出问题),就会找到答案。
- 回到正题,你知道有非
后台线程存在,只能使用System.exit(0)或者Runtime.getRuntime().exit(0),那么我们稍做修改代码。
- 在重新启动之前,我们在
AbstractApplicationContext的doClose(1017)行打个断点
- 一直
F7跟进到DefaultSingletonBeanRegistry的destroySingletons(491)行,在504行打个断点。我们上文说到ComponentA注册为DisposableBean,F9跳到ComponetA。F7进入此方法,F8跟到543行,
F7进入此方法,F8跟到destroyBean(571)行并F8执行
总结
整篇文章不仅是想从表面了解
Bean的世界,而是要走进它的世界。我在写这篇文章的时候,经常问自己这地方你懂了吗?答案模棱两可就是不懂,就需要去仔细品味源码。读源码的作用到底是什么?它会让你见识到一个顶级项目整体的架构,应用了哪些设计模式,一些问题的处理方式等等。这样在日常工作中就可以“借鉴”,让自己的代码是充满着“温度”的好代码。