一、 什么是循环依赖?
A 中有 B,B 中有 A,即循环依赖。
二、Spring 解决方式
Spring 紧紧能解决 scope 为 singleton 的 Bean 循环依赖问题。
-
构造器循环依赖 constructor
Spring 无法解决,直接抛出异常,org.springframework.beans.factory.BeanCurrentlyInCreationException
Requested bean is currently in creation: Is there an unresolvable circular reference?
-
源代码
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
-
-
Set 循环依赖
Spring 通过 提前暴露 创建 Bean 的 ObjectFactory 解决 Set 循环依赖,在创建 B 的时候直接从 A 的 ObjectFactory 中 getObject()
-
源代码
// 缓存提前暴露的 Bean /** Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 缓存创建 singleton Bean 的 ObjectFactory /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 可以看到这里提前暴露的条件是: isSingleton && (allowCircularReferences == true) && bean in creation // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { // 将创建 Bean 的 ObjectFactory 缓存到 singletonFactories 中 this.singletonFactories.put(beanName, singletonFactory); // 将提前暴露的 beanName 从 earlySingletonObjects 中移除 this.earlySingletonObjects.remove(beanName); // 已注册的 Bean this.registeredSingletons.add(beanName); } } } /** * 这个方法在 earlySingletonExposure == true,即创建需要提前暴露的单例 Bean 时调用(其中之一条件) */ protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 从已注册的 singletonObjects 中取 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 上面取不到,且当前是正在创建中的单例时,从 earlySingletonObjects 中取 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 上面取不到,且允许提前引用,从 singletonFactories 中取出提前暴露的 ObjectFactory ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 有提前暴露的 ObjectFactory,则从中取出 Bean singletonObject = singletonFactory.getObject(); // 缓存入 earlySingletonObjects this.earlySingletonObjects.put(beanName, singletonObject); // 清除提前暴露的 ObjectFactory this.singletonFactories.remove(beanName); } } } } return singletonObject; }
-
-
prototype 循环依赖
和构造器循环一样抛出:org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'xxx': Requested bean is currently in creation: Is there an unresolvable circular reference? 异常
三、测试
public class TestA {
private TestB testB;
public TestA() {}
public TestA(TestB testB) {
this.testB = testB;
}
public void a() {
testB.b();
}
// 省略 get/set 方法
}
public class TestB {
private TestC testC;
public TestB() {}
public TestB(TestC testC) {
this.testC = testC;
}
public void b() {
testC.c();
}
// 省略 get/set 方法
}
public class TestC {
private TestA testA;
public TestC() {}
public TestC(TestA testA) {
this.testA = testA;
}
public void c() {
testA.a();
}
// 省略 get/set 方法
}
- 构造器循环依赖
- spring-constructor-cycle-reference.xml
<bean id="testA" class="com.marksman.spring.cycle.TestA">
<constructor-arg index="0" ref="testB"/>
</bean>
<bean id="testB" class="com.marksman.spring.cycle.TestB">
<constructor-arg index="0" ref="testC"/>
</bean>
<bean id="testC" class="com.marksman.spring.cycle.TestC">
<constructor-arg index="0" ref="testA"/>
</bean>
- 测试
try {
new ClassPathXmlApplicationContext("/META-INF/spring-constructor-cycle-reference.xml");
} catch (Exception e) {
Throwable throwable = e.getCause().getCause().getCause();
throw throwable;
}
// 抛出 BeanCurrentlyInCreationException 异常
- Set 循环依赖
- spring-set-cycle-reference.xml
<bean id="testA" class="com.marksman.spring.cycle.TestA">
<property name="testB" ref="testB"/>
</bean>
<bean id="testB" class="com.marksman.spring.cycle.TestB">
<property name="testC" ref="testC"/>
</bean>
<bean id="testC" class="com.marksman.spring.cycle.TestC">
<property name="testA" ref="testA"/>
</bean>
- 测试
ApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/spring-set-cycle-reference.xml");
System.out.println(context.getBean("testA"));
System.out.println(context.getBean("testB"));
System.out.println(context.getBean("testC"));
// 打印出 testA、testB、testC 引用地址
- prototype 循环依赖
- spring-prototype-cycle-reference.xml
<bean id="testA" class="com.marksman.spring.cycle.TestA" scope="prototype">
<property name="testB" ref="testB"/>
</bean>
<bean id="testB" class="com.marksman.spring.cycle.TestB" scope="prototype">
<property name="testC" ref="testC"/>
</bean>
<bean id="testC" class="com.marksman.spring.cycle.TestC" scope="prototype">
<property name="testA" ref="testA"/>
</bean>
- 测试
try {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/spring-prototype-cycle-reference.xml");
System.out.println(context.getBean("testA"));
System.out.println(context.getBean("testB"));
System.out.println(context.getBean("testC"));
} catch (Exception e) {
Throwable throwable = e.getCause().getCause().getCause();
throw throwable;
}
// 抛出 BeanCurrentlyInCreationException 异常
参考
- 《Spring 源码深度解析》