循环依赖的三种方式 - morris131/morris-book GitHub Wiki


title: 循环依赖的三种方式 date: 2018-09-12 18:16:22 categories: spring tags: [spring,循环依赖]

循环依赖的三种方式

循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。

如何检测是否存在循环依赖

Spring容器会将每一个正在创建的Bean标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。

构造器参数循环依赖

通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖。

A.java

package com.morris.spring.cycle;

public class A {

	private B b;

	public A() {
	}

	A(B b) {
		this.b = b;
	}

	public B getB() {
		return b;
	}

	public void setB(B b) {
		this.b = b;
	}

}

B.java

package com.morris.spring.cycle;

public class B {

	private C c;

	B() {

	}

	B(C c) {
		this.c = c;
	}

	public C getC() {
		return c;
	}

	public void setC(C c) {
		this.c = c;
	}

}

C.java

package com.morris.spring.cycle;

public class C {

	private A a;

	C() {

	}

	C(A a) {
		this.a = a;
	}

	public A getA() {
		return a;
	}

	public void setA(A a) {
		this.a = a;
	}

}

spring-cycle-construct.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	<bean id="a" class="com.morris.spring.cycle.A">
		<constructor-arg index="0" ref="b"/>
	</bean>
	
	<bean id="b" class="com.morris.spring.cycle.B">
		<constructor-arg index="0" ref="c"/>
	</bean>
	
	<bean id="c" class="com.morris.spring.cycle.C">
		<constructor-arg index="0" ref="a"/>
	</bean>
</beans>

ConstructCycleTest.java

package com.morris.spring.cycle;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ConstructCycleTest {
	
	public static void main(String[] args) {
		new ClassPathXmlApplicationContext("classpath:spring-cycle-construct.xml");
	}

}

运行结果如下:

"D:\Program Files\Java\jdk1.8.0_172\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.4\lib\idea_rt.jar=65055:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.4\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_172\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\rt.jar;D:\gitPrj\morris-book\后端开发\Java\spring\springDemo\target\classes;C:\Users\wj65651\.m2\repository\org\springframework\spring-context\5.0.8.RELEASE\spring-context-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-aop\5.0.8.RELEASE\spring-aop-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-beans\5.0.8.RELEASE\spring-beans-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-core\5.0.8.RELEASE\spring-core-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-jcl\5.0.8.RELEASE\spring-jcl-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-expression\5.0.8.RELEASE\spring-expression-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\junit\junit\4.11\junit-4.11.jar;C:\Users\wj65651\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\wj65651\.m2\repository\org\aspectj\aspectjrt\1.9.1\aspectjrt-1.9.1.jar;C:\Users\wj65651\.m2\repository\org\aspectj\aspectjweaver\1.9.1\aspectjweaver-1.9.1.jar" com.morris.spring.cycle.ConstructCycleTest
九月 12, 2018 6:01:04 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7ab2bfe1: startup date [Wed Sep 12 18:01:04 CST 2018]; root of context hierarchy
九月 12, 2018 6:01:04 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring-cycle-construct.xml]
九月 12, 2018 6:01:05 下午 org.springframework.context.support.AbstractApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [spring-cycle-construct.xml]: Cannot resolve reference to bean 'b' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-cycle-construct.xml]: Cannot resolve reference to bean 'c' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-construct.xml]: Cannot resolve reference to bean 'a' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [spring-cycle-construct.xml]: Cannot resolve reference to bean 'b' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-cycle-construct.xml]: Cannot resolve reference to bean 'c' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-construct.xml]: Cannot resolve reference to bean 'a' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:625)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:153)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1267)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1124)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
	at com.morris.spring.cycle.ConstructCycleTest.main(ConstructCycleTest.java:8)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-cycle-construct.xml]: Cannot resolve reference to bean 'c' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-construct.xml]: Cannot resolve reference to bean 'a' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:625)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:153)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1267)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1124)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367)
	... 17 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-construct.xml]: Cannot resolve reference to bean 'a' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:625)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:153)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1267)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1124)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367)
	... 29 more
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?
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:339)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:215)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367)
	... 41 more

Process finished with exit code 1

过程分析:

  1. 创建a,首先去"当前创建bean池"查找是否当前bean正在创建,如果没发现,则继续准备其需要的构造器参数"b",并将"a"标识符放到"当前创建bean池"。
  2. 创建b,首先去"当前创建bean池"查找是否当前bean正在创建,如果没发现,则继续准备其需要的构造器参数"c",并将"b"标识符放到"当前创建bean池"。
  3. 创建c,首先去"当前创建bean池"查找是否当前bean正在创建,如果没发现,则继续准备其需要的构造器参数"a",并将"c"标识符放到"当前创建Bean池"。
  4. 创建a,发现该bean标识符在"当前创建bean池"中,因为表示循环依赖,抛出BeanCurrentlyInCreationException

setter singleton循环依赖

setter注入方式构成的循环依赖。对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean循环依赖。通过提前暴露一个单例工厂方法,从而使其他bean能引用到该bean,关键源码如下所示:

	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

SetterSingletonCycleTest.java

package com.morris.spring.cycle;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SetterSingletonCycleTest {
	
	public static void main(String[] args) {
		new ClassPathXmlApplicationContext("spring-cycle-setter-singleton.xml");
	}

}

spring-cycle-setter-singleton.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<bean id="a" class="com.morris.spring.cycle.A">
		<property name="b" ref="b"/>
	</bean>
	
	<bean id="b" class="com.morris.spring.cycle.B">
		<property name="c" ref="c"/>
	</bean>
	
	<bean id="c" class="com.morris.spring.cycle.C">
		<property name="a" ref="a"/>
	</bean>
</beans>

SetterSingletonCycleTest启动不会报错,说明spring自动处理了循环依赖。

过程分析:

  1. 创建a,首先根据无参构造器创建bean,并暴露一个"ObjectFactory"用于返回一个提前暴露一个创建中的bean,并将"a"标识符放到"当前创建bean池",然后进行setter注入"b"。
  2. 创建b,首先根据无参构造器创建bean,并暴露一个"ObjectFactory"用于返回一个提前暴露一个创建中的bean,并将"b"标识符放到"当前创建bean池",然后进行setter注入"c"。
  3. 创建c,首先根据无参构造器创建bean,并暴露一个"ObjectFactory"用于返回一个提前暴露一个创建中的bean,并将"c"标识符放到"当前创建bean池",然后进行setter注入"a"。进行注入"a"时由于提前暴露了"ObjectFactory"工厂,从而使用它返回提前暴露一个创建中的bean。
  4. 最后在依赖注入"b"和"a",完成setter注入。

setter prototype循环依赖

对于prototype作用域bean,Spring容器无法完成依赖注入,因为Spring容器不进行缓存"prototype"作用域的bean,因此无法提前暴露一个创建中的bean。

spring-cycle-setter-prototype.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<bean id="a" class="com.morris.spring.cycle.A" scope="prototype">
		<property name="b" ref="b"/>
	</bean>
	
	<bean id="b" class="com.morris.spring.cycle.B" scope="prototype">
		<property name="c" ref="c"/>
	</bean>
	
	<bean id="c" class="com.morris.spring.cycle.C" scope="prototype">
		<property name="a" ref="a"/>
	</bean>
</beans>

SettlePrototypeCycleTest.java

package com.morris.spring.cycle;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SettlePrototypeCycleTest {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-cycle-setter-prototype.xml");
		context.getBean("a"); // //此时必须要获取Spring管理的实例,因为现在scope="prototype" 只有请求获取的时候才会实例化对象
		context.close();
	}
}

运行结果如下:

"D:\Program Files\Java\jdk1.8.0_172\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.4\lib\idea_rt.jar=65302:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.4\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_172\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\rt.jar;D:\gitPrj\morris-book\后端开发\Java\spring\springDemo\target\classes;C:\Users\wj65651\.m2\repository\org\springframework\spring-context\5.0.8.RELEASE\spring-context-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-aop\5.0.8.RELEASE\spring-aop-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-beans\5.0.8.RELEASE\spring-beans-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-core\5.0.8.RELEASE\spring-core-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-jcl\5.0.8.RELEASE\spring-jcl-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-expression\5.0.8.RELEASE\spring-expression-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\junit\junit\4.11\junit-4.11.jar;C:\Users\wj65651\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\wj65651\.m2\repository\org\aspectj\aspectjrt\1.9.1\aspectjrt-1.9.1.jar;C:\Users\wj65651\.m2\repository\org\aspectj\aspectjweaver\1.9.1\aspectjweaver-1.9.1.jar" com.morris.spring.cycle.SettlePrototypeCycleTest
九月 12, 2018 6:12:07 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7ab2bfe1: startup date [Wed Sep 12 18:12:07 CST 2018]; root of context hierarchy
九月 12, 2018 6:12:07 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring-cycle-setter-prototype.xml]
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [spring-cycle-setter-prototype.xml]: Cannot resolve reference to bean 'b' while setting bean property 'b'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-cycle-setter-prototype.xml]: Cannot resolve reference to bean 'c' while setting bean property 'c'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-setter-prototype.xml]: Cannot resolve reference to bean 'a' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1602)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1354)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1089)
	at com.morris.spring.cycle.SettlePrototypeCycleTest.main(SettlePrototypeCycleTest.java:9)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-cycle-setter-prototype.xml]: Cannot resolve reference to bean 'c' while setting bean property 'c'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-setter-prototype.xml]: Cannot resolve reference to bean 'a' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1602)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1354)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367)
	... 9 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-setter-prototype.xml]: Cannot resolve reference to bean 'a' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1602)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1354)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367)
	... 17 more
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?
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:264)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367)
	... 25 more

Process finished with exit code 1

setAllowCircularReferences循环依赖开关

调用ClassPathXmlApplicationContext的setAllowCircularReferences()方法禁用循环依赖后,用setter注入singleton类型的Bean也会抛出异常。

DisableSetterSingletonCycleTest.class

package com.morris.spring.cycle;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DisableSetterSingletonCycleTest {
	
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-cycle-setter.xml");
		context.setAllowCircularReferences(false); // 禁止循环依赖
		context.refresh(); // 不refresh不生效,原因是之前bean factory已经refresh了
		context.close();
	}

}

运行结果如下:

"D:\Program Files\Java\jdk1.8.0_172\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.4\lib\idea_rt.jar=65376:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.4\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_172\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_172\jre\lib\rt.jar;D:\gitPrj\morris-book\后端开发\Java\spring\springDemo\target\classes;C:\Users\wj65651\.m2\repository\org\springframework\spring-context\5.0.8.RELEASE\spring-context-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-aop\5.0.8.RELEASE\spring-aop-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-beans\5.0.8.RELEASE\spring-beans-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-core\5.0.8.RELEASE\spring-core-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-jcl\5.0.8.RELEASE\spring-jcl-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\org\springframework\spring-expression\5.0.8.RELEASE\spring-expression-5.0.8.RELEASE.jar;C:\Users\wj65651\.m2\repository\junit\junit\4.11\junit-4.11.jar;C:\Users\wj65651\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\wj65651\.m2\repository\org\aspectj\aspectjrt\1.9.1\aspectjrt-1.9.1.jar;C:\Users\wj65651\.m2\repository\org\aspectj\aspectjweaver\1.9.1\aspectjweaver-1.9.1.jar" com.morris.spring.cycle.DisableSetterSingletonCycleTest
九月 12, 2018 6:14:53 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7ab2bfe1: startup date [Wed Sep 12 18:14:53 CST 2018]; root of context hierarchy
九月 12, 2018 6:14:53 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring-cycle-setter-singleton.xml]
九月 12, 2018 6:14:53 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7ab2bfe1: startup date [Wed Sep 12 18:14:53 CST 2018]; root of context hierarchy
九月 12, 2018 6:14:53 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring-cycle-setter-singleton.xml]
九月 12, 2018 6:14:53 下午 org.springframework.context.support.AbstractApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [spring-cycle-setter-singleton.xml]: Cannot resolve reference to bean 'b' while setting bean property 'b'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-cycle-setter-singleton.xml]: Cannot resolve reference to bean 'c' while setting bean property 'c'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-setter-singleton.xml]: Cannot resolve reference to bean 'a' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [spring-cycle-setter-singleton.xml]: Cannot resolve reference to bean 'b' while setting bean property 'b'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-cycle-setter-singleton.xml]: Cannot resolve reference to bean 'c' while setting bean property 'c'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-setter-singleton.xml]: Cannot resolve reference to bean 'a' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1602)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1354)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
	at com.morris.spring.cycle.DisableSetterSingletonCycleTest.main(DisableSetterSingletonCycleTest.java:10)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [spring-cycle-setter-singleton.xml]: Cannot resolve reference to bean 'c' while setting bean property 'c'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-setter-singleton.xml]: Cannot resolve reference to bean 'a' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1602)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1354)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367)
	... 13 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'c' defined in class path resource [spring-cycle-setter-singleton.xml]: Cannot resolve reference to bean 'a' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1602)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1354)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367)
	... 23 more
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?
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:339)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:215)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367)
	... 33 more

Process finished with exit code 1

⚠️ **GitHub.com Fallback** ⚠️