文章目录
- Bean的生命周期
- 三级缓存
- 总结
Bean的生命周期
被Spring管理的对象叫做Bean。Bean的生成步骤如下:
- Spring扫描class得到BeanDefinition
- 根据得到的BeanDefinition去生成bean
- 首先根据class推断构造方法
- 根据推断出来的构造方法,反射,得到一个对象(暂时叫做原始对象)
- 填充原始对象中的属性(依赖注入)
- 如果原始对象中的某个方法被AOP了,那么则需要根据原始对象生成一个代理对象
- 把最终生成的代理对象放入单例池(源码中叫做singletonObjects)中,下次getBean时就直接从单例池拿即可。
三级缓存
三级缓存是通用的叫法。 一级缓存为:singletonObjects 二级缓存为:earlySingletonObjects
三级缓存为**:singletonFactories**
先稍微解释一下这三个缓存的作用,后面详细分析:
singletonObjects中缓存的是已经经历了完整生命周期的bean对象。
earlySingletonObjects比singletonObjects多了一个early,表示缓存的是早期的bean对象。
早期是什么意思?表示Bean的生命周期还没走完就把这个Bean放入了earlySingletonObjects。
singletonFactories中缓存的是ObjectFactory,表示对象工厂,表示用来创建早期bean对象的
工厂。
- singletonObjects:缓存经过了完整生命周期的bean
- earlySingletonObjects:缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,
就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果
要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入
earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是
没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整
生命周期的bean。 - singletonFactories:缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean
的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达
式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出
现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后
直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖
(当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行
Lambda表达式得到一个对象,并把得到的对象放入二级缓存(
(如果当前Bean需要AOP,那么
执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))。 - 其实还要一个缓存,就是earlyProxyReferences,它用来记录某个原始对象是否进行过AOP
了。
反向分析一下singletonFactories
为什么需要singletonFactories?假设没有singletonFactories,只有earlySingletonObjects,
earlySingletonObjects是二级缓存,它内部存储的是为经过完整生命周期的bean对象,Spring原有
的流程是出现了循环依赖的情况下:
- 先从singletonFactories中拿到lambda表达式,这里肯定是能拿到的,因为每个bean实例化之
后,依赖注入之前,就会生成一个lambda表示放入singletonFactories中 - 执行lambda表达式,得到结果,将结果放入earlySingletonObjects中
那如果没有singletonFactories,该如何把原始对象或AOP之后的代理对象放入
earlySingletonObjects中呢?何时放入呢?
首先,将原始对象或AOP之后的代理对象放入earlySingletonObjects中的有两种: - 实例化之后,依赖注入之前:如果是这样,那么对于每个bean而言,都是在依赖注入之前会去
进行AOP,这是不符合bean生命周期步骤的设计的。 - 真正发现某个bean出现了循环依赖时:按现在Spring源码的流程来说,就是
getSingleton(String beanName, boolean allowEarlyReference)中,是在这个方法中判断出
来了当前获取的这个bean在创建中,就表示获取的这个bean出现了循环依赖,那在这个方法中
该如何拿到原始对象呢?更加重要的是,该如何拿到AOP之后的代理对象呢?难道在这个方法中
去循环调用BeanPostProcessor的初始化后的方法吗?不是做不到,不太合适,代码太丑。**最
关键的是在这个方法中该如何拿到原始对象呢?**还是得需要一个Map,预习把这个Bean实例
化后的对象存在这个Map中,那这样的话还不如直接用第一种方案,但是第一种又直接打破了
Bean生命周期的设计。
总结
所以,我们可以发现,现在Spring所用的singletonFactories,为了调和不同的情况,在
singletonFactories中存的是lambda表达式,这样的话,只有在出现了循环依赖的情况,才会执行
lambda表达式,才会进行AOP,也就说只有在出现了循环依赖的情况下才会打破Bean生命周期的设
计,如果一个Bean没有出现循环依赖,那么它还是遵守了Bean的生命周期的设计的。