spring解决Bean的循环依赖
什么是循环依赖
也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。
循环依赖类型
spring Bean 的循环依赖解决主要是根据三级缓存
来实现的。
- 一种是
构造器的相互依赖
(没法解决的原因是三级缓存的前提是已经执行了构造器
。) - 另外一种是
field属性的循环依赖
。
属性的相互依赖
- 属性的相互依赖就是A类的属性中有B,B类的属性中有A,如下:
- 这里仅仅是两个类的循环依赖,当然还有更多的类相互依赖
public class A{
private B b;
}
public class B{
private A a;
}
构造器的依赖
- 构造器的依赖就是A类的构造器需要传入B类对象,B的构造器需要传入A类对象,如下:
public class A{
public A(B b){}
}
public class B{
private B(A a){}
}
如何解决
Spring只能解决属性的循环依赖,构造器的循环依赖是不能解决的。
spring中解决循环依赖的核心思想就是利用三级缓存,先创建Bean,后为各个属性赋值具体什么是三级缓存呢?
三级缓存
三级缓存的实现在org.springframework.beans.factory.support.DefaultSingletonBeanRegistry类中,如下:
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
单例对象缓存池
,beanName->Bean,其中存储的就是实例化,属性赋值成功之后的单例对象
private final Map<String, Object> earlySingletonObjects = newHashMap<>(16);
早期的单例对象也叫提前暴露的单例对象
,beanName->Bean,其中存储的是实例化之后,属性未赋值的单例对象。
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
单例工厂的缓存
,beanName->ObjectFactory
为什么不能解决构造器的循环依赖
Spring解决循环依赖主要是依赖三级缓存,但是的在调用构造方法之前还未将其放入三级缓存之中,因此后续的依赖调用构造方法的时候并不能从三级缓存中获取到依赖的Bean,因此不能解决。
Spring为什么不能解决多例(@SCOP=“prototype”)的循环依赖
多实例Bean是每次调用一次getBean都会执行一次构造方法并且未属性赋值,根本没有三级缓存,因此解决循环依赖。
推荐阅读
-
通过实例解析spring bean之间的关系
-
spring源码分析系列5:ApplicationContext的初始化与Bean生命周期
-
swiper在angularjs中使用循环轮播失效的解决方法
-
解决vuejs 使用value in list 循环遍历数组出现警告的问题
-
Python使用循环神经网络解决文本分类问题的方法详解
-
Python中import导入上一级目录模块及循环import问题的解决
-
Spring启动后获取所有拥有特定注解的Bean实例代码
-
面试必问:Spring循环依赖的三种方式
-
在vue中解决提示警告 for循环报错的方法
-
基于SpringBoot构造器注入循环依赖及解决方式