Spring容器循环依赖包括构造器循环依赖和setter循环依赖,那Spring容器如何解决循环依赖呢?首先让我们来定义循环引用类:
- public class TestA {
- private TestB testB;
- public void a() {
- testB.b();
- }
- public TestB getTestB() {
- return testB;
- }
- public void setTestB(TestB testB) {
- this.testB = testB;
- }
- }
- public class TestB {
- private TestC testC;
- public void b() {
- testC.c();
- }
- public TestC getTestC() {
- return testC;
- }
- public void setTestC(TestC testC) {
- this.testC = testC;
- }
- }
- public class TestC {
- private TestA testA;
- public void c() {
- testA.a();
- }
- public TestA getTestA() {
- return testA;
- }
- public void setTestA(TestA testA) {
- this.testA = testA;
- }
- }
在Spring中将循环依赖的处理分成了3种情况。
1.构造器循环依赖
表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyIn CreationException异常表示循环依赖。
如在创建TestA类时,构造器需要TestB类,那将去创建TestB,在创建TestB类时又发现需要TestC类,则又去创建TestC,最终在创建TestC时发现又需要TestA,从而形成一个环,没办法创建。
Spring容器将每一个正在创建的bean标识符放在一个"当前创建bean池"中,bean标识符在创建过程中将一直保持在这个池中,因此如果在创建bean过程中发现自己已经在"当前创建bean池"里时,将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的bean将从"当前创建bean池"中清除掉。
我们通过一个直观的测试用例来进行分析。
(1)创建配置文件。
- <bean id="testA" class="com.bean.TestA">
- <constructor-arg index="0" ref="testB"/>
- </bean>
- <bean id="testB" class="com.bean.TestB">
- <constructor-arg index="0" ref="testC"/>
- </bean>
- <bean id="testC" class="com.bean.TestC">
- <constructor-arg index="0" ref="testA"/>
- </bean>
(2)创建测试用例。
- @Test(expected = BeanCurrentlyInCreationException.class)
- public void testCircleByConstructor() throws Throwable {
- try {
- new ClassPathXmlApplicationContext("test.xml");
- } catch (Exception e) {
- //因为要在创建testC时抛出;
- Throwable ee1 = e.getCause().getCause().getCause();
- throw e1;
- }
- }
Spring容器循环依赖包括构造器循环依赖和setter循环依赖,那Spring容器如何解决循环依赖呢?首先让我们来定义循环引用类:
- public class TestA {
- private TestB testB;
- public void a() {
- testB.b();
- }
- public TestB getTestB() {
- return testB;
- }
- public void setTestB(TestB testB) {
- this.testB = testB;
- }
- }
- public class TestB {
- private TestC testC;
- public void b() {
- testC.c();
- }
- public TestC getTestC() {
- return testC;
- }
- public void setTestC(TestC testC) {
- this.testC = testC;
- }
- }
- public class TestC {
- private TestA testA;
- public void c() {
- testA.a();
- }
- public TestA getTestA() {
- return testA;
- }
- public void setTestA(TestA testA) {
- this.testA = testA;
- }
- }
在Spring中将循环依赖的处理分成了3种情况。
1.构造器循环依赖
表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyIn CreationException异常表示循环依赖。
如在创建TestA类时,构造器需要TestB类,那将去创建TestB,在创建TestB类时又发现需要TestC类,则又去创建TestC,最终在创建TestC时发现又需要TestA,从而形成一个环,没办法创建。
Spring容器将每一个正在创建的bean标识符放在一个"当前创建bean池"中,bean标识符在创建过程中将一直保持在这个池中,因此如果在创建bean过程中发现自己已经在"当前创建bean池"里时,将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的bean将从"当前创建bean池"中清除掉。
我们通过一个直观的测试用例来进行分析。
(1)创建配置文件。
- <bean id="testA" class="com.bean.TestA">
- <constructor-arg index="0" ref="testB"/>
- </bean>
- <bean id="testB" class="com.bean.TestB">
- <constructor-arg index="0" ref="testC"/>
- </bean>
- <bean id="testC" class="com.bean.TestC">
- <constructor-arg index="0" ref="testA"/>
- </bean>
(2)创建测试用例。
- @Test(expected = BeanCurrentlyInCreationException.class)
- public void testCircleByConstructor() throws Throwable {
- try {
- new ClassPathXmlApplicationContext("test.xml");
- } catch (Exception e) {
- //因为要在创建testC时抛出;
- Throwable ee1 = e.getCause().getCause().getCause();
- throw e1;
- }
- }