spring怎么解决循环依赖
Posted 一梦三十载
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring怎么解决循环依赖相关的知识,希望对你有一定的参考价值。
spring怎么解决循环依赖?
首先会根据 beanName 从单例 bean 缓存中获取,如果不为空则直接返回
主要是从三个缓存中获取 (称他们为3级缓存),分别是:
singletonObjects (1 单例对象的cache)
earlySingletonObjects(2 提前暴光的单例对象的Cache )
singletonFactories (3 单例对象工厂的cache )
getSingleton() 整个过程如下:
首先从一级缓存 singletonObjects 获取,如果没有且当前指定的 beanName 正在创建,
就再从二级缓存中 earlySingletonObjects 获取,如果还是没有获取到且运行 singletonFactories 通过 getObject() 获取,
则从三级缓存 singletonFactories 获取,如果获取到则,通过其 getObject() 获取对象,
并将其加入到二级缓存 earlySingletonObjects 中 从三级缓存 singletonFactories 删除,这样就从三级缓存升级到二级缓存了
从缓存中获取,但是缓存中的数据从哪里添加进来的呢?
提前将创建好但还未进行属性赋值的的Bean放入缓存中
一个 bean 要具备如下条件才会添加至缓存中:
1、单例
2、运行提前暴露 bean
3、当前 bean 正在创建中
如果二级缓存(earlySingletonExposure)存在,singletonFactories 这个三级缓存才是解决 Spring Bean 循环依赖的诀窍所在。
同时这段代码发生在 createBeanInstance() 方法之后,也就是说这个 bean 其实已经被创建出来了,但是它还不是很完美(没有进行属性填充和初始化)
,但是对于其他依赖它的对象而言已经足够了(可以根据对象引用定位到堆中对象),能够被认出来了,
所以 Spring 在这个时候选择将该对象提前曝光出来让大家认识认识
所以我们基本上可以确定 Spring 解决循环依赖的方案了:Spring 在创建 bean 的时候并不是等它完全完成,
而是在创建过程中将创建中的 bean 的 ObjectFactory 提前曝光(即加入到 singletonFactories 缓存中),
这样一旦下一个 bean 创建的时候需要依赖 bean ,则直接使用 ObjectFactory 的 getObject() 获取了,也就是 getSingleton()中的代码片段了。
描述下就上面那个循环依赖 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 完成初始化。到这里整个链路就已经完成了初始化过程了
总体就是 把循环的A初始化放到通过 ObjectFactory 放到 2级缓存 。。。 C尝试去缓存中 get A C拿到 A 对象后顺利完成初始化,然后将自己添加到一级缓存中,
回到 B ,B 也可以拿到 C 对象,完成初始化
Spring对单例的底层实现,到底是饿汉式单例还是懒汉式单例呢?
Spring框架对单例的支持是采用单例注册表的方式进行实现的
以上是关于spring怎么解决循环依赖的主要内容,如果未能解决你的问题,请参考以下文章
spring的循环依赖是什么,设计的时候怎么避免,而spring又是怎么解决的?