美文网首页
spring循环依赖的三种方式

spring循环依赖的三种方式

作者: 垂直居中的句号 | 来源:发表于2021-05-14 18:08 被阅读0次
    1. 构造器的方式
      通过构造器参数注入,形成的循环依赖,无法解决,因为执行构造方法初始话之前会先将A放在正在创建的Bean池中,创建完成后移除,当A依赖于B ,B又依赖于A时,创建A时放在了正在创建Bean池中,需要B时创建B,将B放在了正在创建Bean池,而B需要A,此时A已经在正在创建Bean池中,所以会报错。

    2.setter方式原型,prototype
    prototype 每次getBean都会返回新的bean. 考虑线程安全和并发的时候 ,考虑使用prototype。
    循环依赖情况下,prototype的,spring容器不进行缓存,无法提前暴露一个创建中的Bean.

    3.setter方式单例。
    三级缓存
    一级缓存:已经初始化完成的bean 单例池
    二级缓存:只实例化但是没有注入属性的bean 集合
    三级缓存:工厂bean的缓存集合 (解决代理问题) 如果需要创建代理返回的代理对象,如果不需要代理返回的原始对象。

    A依赖于B ,B依赖于A

    getBean(A)-》从一级缓存中查找===》没有的话找二级 ==》没有的话找三级=》都没有创建A的实例==》

    A的原始对象提前暴露放在三级缓存中

    ==》A填充属性时需要 B => 从一级缓存中查找===》没有的话找二级 ==》没有的话找三级=》都没有创建B的实例==》
    B的原始对象提前暴露放在三级缓存中 ( 在B未初始化完成而有其他类需要B时执行三级缓存中 需要代理的话返回代理对象==》把B放在二级缓存中 )

    ==>B填充属性时需要 A=> 从一级缓存中查找===》没有的话找二级 ==》在三级缓存中找到A的引用。

    ==》 三级缓存中A 需要代理的话返回代理对象==》把A放在二级缓存中

    ==》B使用二级缓存中的A

    ==》初始化完成==》B进入一级缓存中。

    ==》A的填充完属性B ==》初始化完成 ==>A进入一级缓存中。

    为什么使用第三级工厂缓存?
    如果只有二级缓存的话,A创建的最后阶段可能创建代理,生成代理对象,而B中初始化已经完成,但是使用的是A的原始引用,导致不一致。

    为什么不提前执行完代理逻辑,放入二级缓存中?
    因为A在实例化完之后,并不知道是否有B依赖A,如果没有的话,A创建后期还是会再执行一遍扩展,导致执行重复。

    相关文章

      网友评论

          本文标题:spring循环依赖的三种方式

          本文链接:https://www.haomeiwen.com/subject/bdbqjltx.html