自学内容网 自学内容网

【Spring】循环引用 解决流程,只用一二级缓存?

循环引用

循环引用

循环依赖:循环依赖其实就是循环引用,也就是bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于A

循环依赖在spring中是允许存在,spring框架依据三级缓存已经解决了大部分的循环依赖

  1. 三级缓存

    • 一级缓存:单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象

    • 二级缓存:缓存早期的bean对象(生命周期还没走完)

    • 三级缓存:缓存的是ObjectFactory,表示对象工厂,可以用来在需要时生成Bean的代理对象。(lambda表达式),打破循环

  2. creatingSet

    • Spring使用creatingSet来存储当前正在创建的Bean的Set,用于判断是否出现循环依赖。

    • 当检测到循环依赖时,Spring会从二级缓存中寻找半成品Bean,或者从三级缓存中获取Bean对应的Bean工厂对象(如lambda表达式)。

  3. earlyProxyReferences

    • earlyProxyReferences用于存储那些因为循环依赖而提前进行了AOP处理的Bean。

    • 通过这个Set,Spring可以避免在Bean初始化完成后,重复在beanPostProcessAfterInitialization()方法中对已经AOP过的对象再次进行AOP操作。

  4. @Lazy解决循环依赖

    • 使用@Lazy注解,Spring通过CGLib生成代理对象,在依赖注入时延迟加载Bean,避免Bean生命周期中的循环依赖问题。

    • @Lazy通过代理对象的方式,使得Bean在需要时才初始化,解决了Bean的循环依赖问题。

  5. 综合机制

    • 三级缓存creatingSetearlyProxyReferences@Lazy代理机制,加上Spring的AOP处理,五者共同作用,才能真正彻底解决循环依赖的问题。

这里@Lazy注解底层就是用aop生成的代理对象,最后走的createAopProxy方法

构造器初始化,会把依赖注入提前,获取不到实例A对象

在这里插入图片描述

循环引用解决流程

  1. 先实例A对象,同时会创建ObjectFactory对象存入三级缓存singletonFactories
  2. A在初始化的时候需要B对象,这个走B的创建的逻辑
  3. B实例化完成,也会创建ObjctFactory对象存入三级缓存singletonFactories
  4. B需要注入A,通过三级缓存中获取ObjectFactory来生成一个A的对象同时存入二级缓存,这个是有两种情况,一个是可能是A的普通对象,另外一个是A的代理对象,都可以让ObjectFactory来生产对应的对象,这也是三级缓存的关键
  5. B通过从通过二级缓存 earlySingletonObjects 获得到A的对象后可以正常注入,B创建成功,存入一级缓存singletonObjects
  6. 回到A对象初始化,因为B对象已经创建完成,则可以直接注入B,A创建成功存入一次缓存singletonObjects
  7. 二级缓存中的临时对象A清除

为什么不只用一二级缓存?🔴

Spring在循环依赖中不能只使用一、二级缓存,主要原因是三级缓存中的**ObjectFactory**(用于延迟创建代理对象)是关键。

如果只用一、二级缓存:

  • 代理对象必须在创建Bean的早期阶段就生成,而代理的生成通常需要等到Bean的后置处理器(BeanPostProcessor)完成后才能进行。
  • 三级缓存通过ObjectFactory延迟生成代理对象,确保在Bean初始化过程中按需创建代理,避免提前或重复生成代理对象。

因此,三级缓存用于处理AOP代理的延迟创建,确保在复杂依赖场景下正常注入Bean,避免提前生成或重复AOP增强。


原文地址:https://blog.csdn.net/qq_45651302/article/details/143832091

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!