什么是循环依赖
这个很好理解 我们在bean的生命周期中说了
bean实例化的时候 要注入属性值 这些属性可能就包括一些其他的bean
这个很常见 比如你的一个bean里面 @autowired 注入了一些其他的bean
但是A里面注入了B ,B里面又注入了A,
这时候容器就犯难了 加载A的时候B还没好 加载B的时候A还没好
比如:
那么spring是怎么解决它的呢?
思路:
当我们往A里面注入B 但是B还没有完全初始化完成为一个完整的bean。 这时候 spring直接把那个 刚刚实例化还没有初始化(没有注入属性)的B 提前暴露 注入给A,等A初始化完成之后,再把里面的B初始化。
三级缓存
所谓的三级缓存 不要理解成 redis那种把数据缓存起来 快速取。这里的三级缓存 名字起的不太好,它真实的意思 应该是 三个容器存储不同时期(创建初期 创建中期 创建末期)不同状态下的bean。 注意它不是一个东西 存三个地方 而已一个东西的三个时期(每个时期有差别)分别存在三个地方。
- 第一行 :完整的bean存储的位置 我们使用的bean就是从这里取的,我们叫一级缓存
- 第三行:早期的单例池 缓存半成品对象(创建了bean 属性还没被注入) 且当前对象以及被引用了 我们叫二级缓存
- 第二行:单例bean的工厂 缓存半成品对象 且对象没有被引用,使用时创建bean
具体过程如下:
当创建Bean A时,如果发现存在对Bean B的依赖,会先检查singletonObjects缓存中是否存在Bean
B的实例,如果存在,则直接返回。如果singletonObjects缓存中不存在Bean
B的实例,会继续检查earlySingletonObjects缓存中是否存在Bean B的实例。如果存在,则将该半成品的Bean
B实例返回,以满足循环依赖的需要。如果earlySingletonObjects缓存中也不存在Bean B的实例,那么说明Bean
B还未创建,此时会调用相应的Bean工厂创建Bean B,并将工厂对象放入singletonFactories缓存中。创建Bean B的过程中,如果发现Bean B又依赖于Bean A,会递归地触发创建Bean A的过程。
当Bean A和Bean B都创建完成后,会依次进行初始化和属性注入等操作。
最后,将Bean A和Bean B分别放入singletonObjects缓存中,以供后续获取。