以前十一假期,基于SpringBoot实现集成公司业务和通用封装的starter,有点相似支付宝的Sofa-Boot。在实现过程当中,不断优化的过程发现对源码理解很差,starter很容易写的不那么“聪明”。因此就趁着假期一点点跟着源码阅读了起来,今天来分享一篇总结简单Bean的生命周期。html
我阅读源码的过程当中,一般分两步走:跳出来,看全景;钻进去,看本质。先了解Bean的生命周期图对其有大致了解,该技术在大脑中有了一个“简单”的构图后。再阅读相关源码去确认本身在看全景时的大脑构图是否合理。这个过程其实也适用于面对新环境,先熟悉本身所处项目的业务,再过技术栈与代码相关细节。钻进去看本质的过程每每是“煎熬的”,须要坚持与不断的思考。git
Spring源码版本: 5.0.9.RELEASEgithub
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类泛化体系远比此复杂多。spring
@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
分别表明进入方法内部、跳到下一行、跳到下一个断点处。apache
F8
按照索引目录跟到759行 设计模式
F7
进入此方法,进入到抽象类AbstractBeanFactory
缓存
F7
进入doGetBean方法 bash
DefaultSigletonBeanRegistry
中的getSingleton
Map
:
这三级缓存具体做用咱们在populate
阶段再分析架构
返回到AbstractBeanFactory
的doGetBean(246)
,F8
接着跟到315行 app
F7
跟进去,咱们看到到第222行调用了getObject()
getObject()
F7
跟进去其实调用的就是createBean
F7
跟进去,到了AbstractAutowireCapableBeanFacotory
的createBean(456)
, 在这个方法内找到495行, F7
进入此方法
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
,目的为了解决循环引用的问题,那么什么是循环引用的状况与如何解决的呢?且看下文分解。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)
,接着分析注入的过程
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
跳到此位置
F7
进入descriptor.resolveCandidate(1135)
行,来到DependencyDescriptor
的resolveCandidate(248)
行
F7
进入beanFactory.getBean(251)
行,一直跟到AbstractBeanFacotory
的doGetBean(239)
行,如下过程都是建立Componet B
的过程,因此汇集在一块儿,等Componet B
中须要注入Component A
时咱们在分开。F9
跳到这
F7
进入,F8
跟到doCreateBean(495)
行
F7
进入,F8
跟到doCreateBean(572)
行
populate ComponentA
,F7
进入populateBean
方法。populate ComponentA
时,确定最终会去试图建立ComponentA
,也会回到AbstractBeanFacotry
的doGetBean(239)
行
F7
进入getSingleton(246)
行,一直跟到DefaultSingletonBeanRegistry
的getSingleton(176)
行,F8
跟到185行
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
, 因此这块会回调setBeanFactory
F8
执行完invokeAwareMethods
$setBeanFactory()...
F8
跳回到initializeBean(1691)
行
F7
跟进去,到了AbstractAutowireCapableBeanFacotry
的applyBeanPostProcessorsBeforeInitialization(411)
行
*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的setApplicationContext
F8
跟到invokeAwareInterfaces(102)
这个方法的最后,看下打印结果。
*Aware
接口,生命周期要早于*AwareProcessor
。AbstractAutowireCapableBeanFacotry
的initializeBean(1678)
中的invokeInitMethods(1695)
行,F7
进入此方法,再F8
跟到invokeInitMethods(1758)
行
F8
执行afterPropertiesSet
,由于ComponentA implements InitializingBean
,因此控制台确定会打印$afterPropertiesSet()...
,以下图所示:
F8
下面的1767行就是执行,目标init方法
F8
跟回到AbstractAutowireCapableBeanFacotry
的applyBeanPostProcessorsAfterInitialization(1703)
行
F8
跟到AbstractAutowireCaplableBeanFacotry
的doCreateBean(614)
行
Bean
注册为DisposableBean
会随着容器
销毁而销毁。F8
一直跟回到DefaultSingletonBeanRegistry
的getSingleton(248)
行
F7
进入到此方法,看看建立Bean的最后一步
earlySingletonObjects
转存到以及缓存singletonObjects
,以上过程咱们完成了Bean
的整个建立过程,Spirng
之因此处理的这么“松散”(低耦合),其实就是在Bean
整个生命周期过程当中,提供给用户更好的拓展能力。结合本身的业务场景,灵活定制。Runtime.getRuntime().addShutdownHook(Thread hook)
,写段测试代码。
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
的世界。
后台线程
存在,只能使用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
的世界,而是要走进它的世界。我在写这篇文章的时候,常常问本身这地方你懂了吗?答案模棱两可就是不懂,就须要去仔细品味源码。读源码的做用究竟是什么?它会让你见识到一个顶级项目总体的架构,应用了哪些设计模式,一些问题的处理方式等等。这样在平常工做中就能够“借鉴”,让本身的代码是充满着“温度”的好代码。