共计 1797 个字符,预计需要花费 5 分钟才能阅读完成。
spring 学习之源码分析 –bean 的创建以及之前的文章,都提到了循环依赖,那这次咱们来看看 spring 是如何解决循环依赖的。
在 spring 学习之注入中,我们看到了两种的注入方式,一个是构造函数注入,一个是 setter 注入。我们分别看看这两种方式,各是什么样的情况。
构造
TestA 的构造函数注入了 TestB,TestB 的构造函数注入了 TestA。
public class TestA {
private TestB testB;
public TestA(@Autowired TestB testB) {this.testB = testB;}
}
public class TestB {
private TestA testA;
public TestB(@Autowired TestA testA) {this.testA = testA;}
}
测试代码
@Test
public void testCircleByConstructor() {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(TestA.class, TestB.class);
context.refresh();}
运行结果
主要的错误如下:
Error creating bean with name ‘testA’: Requested bean is currently in creation: Is there an unresolvable circular reference
下面看看整个流程图:
setter 注入
下面看看 setter 注入的时候,是怎么处理的
单例
TestC 的 setter 注入了 TestD,TestD 的 setter 注入了 TestC。跟上面构造函数不同的是,这边是无参构造,所以可以先实例化,再进行属性设置。
public class TestC {
@Autowired
private TestD testD;
}
public class TestD {
@Autowired
private TestC testC;
}
测试代码
@Test
public void testCircleBySet() {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(TestC.class, TestD.class);
context.refresh();}
下面看看整个流程图:
多例
TestE 的 setter 注入了 TestF,TestF 的 setter 注入了 TestE。跟上面不同的是,这边是 Scope 是 prototype。
因为是多例的,所以容器初始化的时候,并不会实例化,只能我们自己调用的时候实例化。
@Scope("prototype")
public class TestE {
@Autowired
private TestF testF;
}
@Scope("prototype")
public class TestF {
@Autowired
private TestE testE;
}
测试代码
@Test
public void testCircleByPrototype() {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(TestE.class, TestF.class);
context.refresh();
context.getBean("testE");
}
运行结果:
主要的错误如下:
Error creating bean with name ‘testE’: Requested bean is currently in creation: Is there an unresolvable circular reference
下面看看整个流程图:
多例的判断,是通过 prototypesCurrentlyInCreation 来的,创建前设值进去,创建后移除,如果循环依赖,就会出现还没移除又设值的情况,就抛异常了。
DependsOn
创建 bean 之前,会通过 isDependent 判断是否循环依赖,没有循环依赖通过 registerDependentBean 注册依赖