spring源码深度解析— IOC 之 循环依赖处理

  • 时间:
  • 浏览:24

注意,这里后要函数的循环调用,是对象的相互依赖关系。循环调用随便说说就让 原本死循环,除非有终结条件。

Spring中循环依赖场景有:

(1)构造器的循环依赖

(2)field属性的循环依赖。 

这名 办法主就让 从原本缓存中获取,分别是:singletonObjects、earlySingletonObjects、singletonFactories,三者定义如下:

这三级缓存分别指:

(1)singletonFactories : 单例对象工厂的cache

(2)earlySingletonObjects :提前暴光的单例对象的Cache

(3)singletonObjects:单例对象的cache

在 doGetBean() 中,首先会根据 beanName 从单例 bean 缓存中获取,机会不为空则直接返回。

从这段代码我们我们我们 儿可可不还能不能不能看出 singletonFactories 这名 三级缓存才是处置 Spring Bean 循环依赖的诀窍所在。同時 这段代码居于在 createBeanInstance() 办法就让,也就让 说这名 bean 随便说说机会被创建出来了,就让 它还后要很完美(没法进行属性填充和初始化),就让 对于有些依赖它的对象而言机会足够了(可可不还能不能不能根据对象引用定位到堆中对象),可不还能不能被认出来了,什么都有 Spring 在这名 就让取舍将该对象提前曝光出来让我们我们我们 儿认识认识。

检测循环依赖相对比较容易,Bean在创建的就让可可不还能不能不能给该Bean打标,机会递归调用回来发现正在创建中得话,即说明了循环依赖了。

上加至一级缓存,同時 从二级、三级缓存中删除。这名 办法在我们我们我们 儿创建 bean 的链路暗含哪个地方引用呢?其随便说说前面博客 LZ 机会提到过了,在 doGetBean() 处置不同 scope 时,机会是 singleton,则调用 getSingleton(),如下:

循环依赖随便说说就让 循环引用,也就让 原本或则原本以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图所示:

顶端是从缓存中获取,就让 缓存中的数据从哪里上上加来的呢?总是往下跟会发现在 doCreateBean() ( AbstractAutowireCapableBeanFactory ) 中,有没法一段代码:

我们我们我们 就让 Spring 处置 singleton bean 的关键因素所在,我称我们我们我们 为三级缓存,第一级为 singletonObjects,第二级为 earlySingletonObjects,第三级为 singletonFactories。这里我们我们我们 儿可可不还能不能不能通过 getSingleton() 看到我们我们我们 是如可配合的,这分析该办法就让,提下其中的 isSingletonCurrentlyInCreation() 和 allowEarlyReference

getSingleton() 整个过程如下:首先从一级缓存 singletonObjects 获取,机会没法且当前指定的 beanName 正在创建,就再从二级缓存中 earlySingletonObjects 获取,机会还是没法获取到且运行 singletonFactories 通过 getObject() 获取,则从三级缓存 singletonFactories 获取,机会获取到则,通过其 getObject() 获取对象,并将其加入到二级缓存 earlySingletonObjects 中 从三级缓存 singletonFactories 删除,如下:

我们我们我们 儿先从加载 bean 最初始的办法 doGetBean() 就让刚现在刚开始。

机会 earlySingletonExposure == true 得话,则调用 addSingletonFactory() 将我们我们我们 上加到缓存中,就让 原本 bean 要具备如下条件才会上加至缓存中:

addSingletonFactory() 代码如下:

对于构造器的循环依赖,Spring 是无法处置的,可不还能不能抛出 BeanCurrentlyInCreationException 异常表示循环依赖,什么都有下面我们我们我们 儿分析的后要基于 field 属性的循环依赖。

介绍到这里我们我们我们 儿发现三级缓存 singletonFactories 和 二级缓存 earlySingletonObjects 中的值后要出处了,那一级缓居于哪里设置的呢?在类 DefaultSingletonBeanRegistry 中可可不还能不能不能发现这名  addSingleton() 办法,源码如下:

到这里,关于 Spring 处置 bean 循环依赖就机会分析完毕了。最就让 描述下就顶端那个循环依赖 Spring 处置的过程:首先 A 完成初始化第一步并将个人提前曝光出来(通过 ObjectFactory 将个人提前曝光),在初始化的就让,发现个人依赖对象 B,此时就会去尝试 get(B),这名 就让发现 B 还没法被创建出来,就让 B 就走创建流程,在 B 初始化的就让,同样发现个人依赖 C,C 也没法被创建出来,这名 就让 C 又就让刚现在刚开始初始化程序,就让 在初始化的过程中发现个人依赖 A,于是尝试 get(A),这名 就让机会 A 机会上加至缓存中(一般后要上加至三级缓存 singletonFactories ),通过 ObjectFactory 提前曝光,什么都有可可不还能不能不能通过 ObjectFactory.getObject() 拿到 A 对象,C 拿到 A 对象后顺利完成初始化,就让 将个人上加到一级缓存中,回到 B ,B 也可可不还能不能不能拿到 C 对象,完成初始化,A 可可不还能不能不能顺利拿到 B 完成初始化。到这里整个链路就机会完成了初始化过程了。

至此,Spring 关于 singleton bean 循环依赖机会分析完毕了。什么都有我们我们我们 儿基本上可可不还能不能不能取舍 Spring 处置循环依赖的方案了:Spring 在创建 bean 的就让并后要等它删剪完成,就让 在创建过程中将创建中的 bean 的 ObjectFactory 提前曝光(即加入到 singletonFactories 缓存中),原本一旦下原本 bean 创建的就让时要依赖 bean ,则直接使用 ObjectFactory 的 getObject() 获取了,也就让  getSingleton()中的代码片段了。

也就让 我们我们我们 儿上一篇文章中讲的最后一要素,提前将创建好但还未进行属性赋值的的Bean放在去缓存中。

原本就从三级缓存升级到二级缓存了。

Spring 只处置 scope 为 singleton 的循环依赖,对于scope 为 prototype 的 bean Spring 无法处置,直接抛出 BeanCurrentlyInCreationException 异常。