Spring循环依赖问题
一、spring循环依赖
Spring解决循环依赖是有前置条件的
出现循环依赖的Bean必须要是单例
依赖注入的方式不能全是构造器注入的方式(很多博客上说,只能解决setter方法的循环依赖,这是错误的)
其中第一点应该很好理解,第二点:不能全是构造器注入是什么意思呢?我们还是用代码说话
@Component
public class A {
// @Autowired
// private B b;
public A(B b) {
}
}
@Component
public class B {
// @Autowired
// private A a;
public B(A a){
}
}
在上面的例子中,A中注入B的方式是通过构造器,B中注入A的方式也是通过构造器,这个时候循环依赖是无法被解决,如果你的项目中有两个这样相互依赖的Bean,在启动时就会报出以下错误:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
为了测试循环依赖的解决情况跟注入方式的关系,我们做如下四种情况的测试
依赖情况 | 依赖注入方式 | 循环依赖是否被解决 |
---|---|---|
AB相互依赖(循环依赖) | 均采用setter方法注入 | 是 |
AB相互依赖(循环依赖) | 均采用构造器注入 | 否 |
AB相互依赖(循环依赖) | A中注入B的方式为setter方法,B中注入A的方式为构造器 | 是 |
AB相互依赖(循环依赖) | B中注入A的方式为setter方法,A中注入B的方式为构造器 | 否 |
从上面的测试结果我们可以看到,不是只有在setter方法注入的情况下循环依赖才能被解决,即使存在构造器注入的场景下,循环依赖依然被可以被正常处理掉。
二、spring解决循环依赖(三级缓存)
(1)、三级缓存定义
看源码的DefaultSingletonBeanRegistry中有三个 Map 对象
/** Cache of singleton objects: bean name to bean instance. */
/** 一级缓存,可以理解为单例池 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
/** 三级缓存,单例工厂缓存 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
/** 二级缓存,早期单例对象缓存 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
singletonObjects:存放初始化后的单例对象,也就是完成的 bean 对象
earlySingletonObjects:存放实例化,未完成初始化的单例对象(未完成属性注入的对象),也是用来解决性能问题
singletonFactories:存放 ObjectFactory 对象,存放的是工厂对象,也是用来解决 aop 的问题
(2)、核心方法refresh(刷新)
finishBeanFactoryInitialization方法
重点解析:解决循环依赖。
三级缓存可以解决循环依赖。
-
singletonObjects:一级缓存(单例池:存放经历了完整生命周期的bean对象)
-
earlySingletonObjects:二级缓存(存放早期暴露出来的bean对象,bean生命周期尚未结束)
-
singletonFactories:三级缓存----单例工厂(存放可以生成bean工厂–准备生产)
3个map+四个方法(解决循环依赖) -
getSingleton
-
doCreateBean:添加bean
-
populateBean:属性填充
-
addSingleton:将bean设置到一级缓存,且删除二级和三级