简单说说 spring构造器循环依赖 为什么无法解决(源码解析)
源码
在DefaultSingletonBeanRegistry.getSingleton(获取或者创建单例)方法中,会调用beforeSingletonCreation方法
该方法会向singleCurrentlyInCreation列表中插入一个beanName。
singleCurrentlyInCreation 是一个Set的列表,如果列表中已经存在数据,则会返回false。
protected void beforeSingletonCreation(String beanName) {
//向singleCurrentlyInCreation 列表插入当前的beanName
//如果beanName已经存在,则会报错
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
分析
有两个类,分别是 CycleExampleA 和 CycleExampleB
@Component
public class CycleExampleA {
private CycleExampleB b;
public CycleExampleA(CycleExampleB b) {
this.b = b;
}
}
@Component
public class CycleExampleB {
private CycleExampleA cycleExampleA;
public CycleExampleB(CycleExampleA cycleExampleA) {
this.cycleExampleA = cycleExampleA;
}
}
spring在有构造器注入的情况下,如果有循环依赖,过程是这样的
- 在spring中,假设我先去创建CycleExampleA,这个时候CycleExampleA会被插入到singleCurrentlyInCreation,被标记为正在创建。
- 然后由于当前类有构造器,所以,spring会用我们的构造器进行创建
- 在使用构造器的时候,发现依赖CycleExampleB,则会先去创建CycleExampleB
- 在创建B的时候,会发现构造器中依赖CycleExampleA,则会先去创建CycleExampleA。
- 这个时候,在创建CycleExampleA的时候,发现无法将CycleExampleA插入singleCurrentlyInCreation,就会报错。
总结
在spring中,bean暴露的最早期是在bean实例化完成之后,因此,如果有构造器注入循环依赖,无法像set注入那样通过三级缓存进行处理。
其实循环引用的存在,就是不符合代码设计规范的一个事情,我们需要杜绝循环依赖,甚至是同级调用。
传送阵
set注入是如何解决循环依赖问题:简单说说 spring 是如何处理循环依赖问题的(源码解析)-CSDN博客