【Spring】循环引用 解决流程,只用一二级缓存?
循环引用
循环引用
循环依赖:循环依赖其实就是循环引用,也就是bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于A
循环依赖在spring中是允许存在,spring框架依据三级缓存已经解决了大部分的循环依赖
-
三级缓存
-
一级缓存:单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象
-
二级缓存:缓存早期的bean对象(生命周期还没走完)
-
三级缓存:缓存的是ObjectFactory,表示对象工厂,可以用来在需要时生成Bean的代理对象。(lambda表达式),打破循环
-
-
creatingSet
-
Spring使用
creatingSet
来存储当前正在创建的Bean的Set,用于判断是否出现循环依赖。 -
当检测到循环依赖时,Spring会从二级缓存中寻找半成品Bean,或者从三级缓存中获取Bean对应的Bean工厂对象(如
lambda
表达式)。
-
-
earlyProxyReferences
-
earlyProxyReferences
用于存储那些因为循环依赖而提前进行了AOP处理的Bean。 -
通过这个Set,Spring可以避免在Bean初始化完成后,重复在
beanPostProcessAfterInitialization()
方法中对已经AOP过的对象再次进行AOP操作。
-
-
@Lazy解决循环依赖
-
使用
@Lazy
注解,Spring通过CGLib生成代理对象,在依赖注入时延迟加载Bean,避免Bean生命周期中的循环依赖问题。 -
@Lazy
通过代理对象的方式,使得Bean在需要时才初始化,解决了Bean的循环依赖问题。
-
-
综合机制
- 三级缓存、creatingSet、earlyProxyReferences、
@Lazy
代理机制,加上Spring的AOP处理,五者共同作用,才能真正彻底解决循环依赖的问题。
- 三级缓存、creatingSet、earlyProxyReferences、
这里@Lazy注解底层就是用aop生成的代理对象,最后走的createAopProxy方法
构造器初始化,会把依赖注入提前,获取不到实例A对象
循环引用解决流程
- 先实例A对象,同时会创建ObjectFactory对象存入三级缓存singletonFactories
- A在初始化的时候需要B对象,这个走B的创建的逻辑
- B实例化完成,也会创建ObjctFactory对象存入三级缓存singletonFactories
- B需要注入A,通过三级缓存中获取ObjectFactory来生成一个A的对象同时存入二级缓存,这个是有两种情况,一个是可能是A的普通对象,另外一个是A的代理对象,都可以让ObjectFactory来生产对应的对象,这也是三级缓存的关键
- B通过从通过二级缓存 earlySingletonObjects 获得到A的对象后可以正常注入,B创建成功,存入一级缓存singletonObjects
- 回到A对象初始化,因为B对象已经创建完成,则可以直接注入B,A创建成功存入一次缓存singletonObjects
- 二级缓存中的临时对象A清除
为什么不只用一二级缓存?🔴
Spring在循环依赖中不能只使用一、二级缓存,主要原因是三级缓存中的**ObjectFactory
**(用于延迟创建代理对象)是关键。
如果只用一、二级缓存:
- 代理对象必须在创建Bean的早期阶段就生成,而代理的生成通常需要等到Bean的后置处理器(
BeanPostProcessor
)完成后才能进行。 - 三级缓存通过
ObjectFactory
延迟生成代理对象,确保在Bean初始化过程中按需创建代理,避免提前或重复生成代理对象。
因此,三级缓存用于处理AOP代理的延迟创建,确保在复杂依赖场景下正常注入Bean,避免提前生成或重复AOP增强。
原文地址:https://blog.csdn.net/qq_45651302/article/details/143832091
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!