Spring循环依赖的解决方法

问题

Spring的循环依赖是什么?就是两个Bean之间互相依赖,比如A的Bean中依赖B,B的Bean依赖A
TeatA.java

1
2
3
4
5
6
7
8
9
10
11
package com.lnw.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TestA {
public TestB testB;
@Autowired
public void setTestB(TestB testB) {
this.testB = testB;
}
}

TestB.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.lnw.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TestB {
public TestA testA;

@Autowired
public void setTestA(TestA testA){
this.testA = testA;
}
}

此时如果运行Spring,是不会报错的,证明Spring可以自己解决循环依赖,那Spring是怎么解决的呢

解密

这里需要大家了解下Spring的Bean的声明周期,不清楚的可以看这篇Spring-Bean的生命周期博客
长话短说,先说下Spring的解决办法,如果Spring发现一个Bean(当前Bean为A)存在循环依赖时,此时就会为当前Bean封装一个ObjectFactory,放进一个类似IOC容器的HashMap中 singletonFactories ,放进之后,继续创建Bean A,当到了Bean的生命周期的populateBean的属性解析的时候,发现依赖Bean B,就去创建Bean B;在创建Bean B的时候发现B存在循环依赖,就把当前B封装成一个ObjectFactory放进 singletonFactories (注意,此时Map中已经有两个ObjectFactory)

Spring获取单例Bean的流程

这里有必要讲一下Spring获取单例Bean的流程,在getSingleton方法中
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先尝试从IOC容器中获取Bean
Object singletonObject = this.singletonObjects.get(beanName);
// 如果获取不到Bean,并且解析出当前Bean存在循环依赖
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 尝试从earlySingletonObjects中获取Bean
// earlySingletonObjects跟singletonFactories是相辅相成的
// singletonFactories中存放ObjectFactory,ObjectFactory可以返回一个实例
// earlySingletonObjects可以存放ObjectFactory返回的实例
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果不在earlySingletonObjects中
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// 判断是否有ObjectFactory,如果有,就通过ObjectFactory创建
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 将实例存放进earlySingletonObjects
this.earlySingletonObjects.put(beanName, singletonObject);
// 将ObjectFactory移除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}

注释已经写明白了,先从IOC容器中获取,如果没有就判断是否有循环依赖,有循环依赖则从singletonFactories和earlySingletonObjects获取

继续

我们继续讲解上面的流程,我们讲到在创建B的Bean时发现循环依赖,就把B封装成ObjectFactory并放进singletonFactories,然后在Bean生命周期的populateBean的方法解析属性时发现存在依赖A的Bean,此时又要走创建Bean A的流程,但是走到org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton这个方法时(也就是上面Spring的源代码),会从singletonFactories获取A的ObjectFactory,由ObjectFactory创建对象,并且赋值给B的Bean,此时B的Bean是指向A的实例(尽管A的Bean还没有创建,但是实例,也就是对象已经存在),这样一来B的Bean就会创建完成,需要添加进IOC容器
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton

1
2
3
4
5
6
7
8
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

添加进IOC容器前需要擦除earlySingletonObjects和singletonFactories有关B的所有信息
这样的话,B的Bean已经创建完成了,回退到解析A的属性时,此时A需依赖Bean B,因为Bean B已经创建,所以直接将Bean B赋给A的属性,就这样循环依赖解决了。

再重复一次

当Spring创建TestA时,在doCreate方法中,有这么一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 这个判断很重要,Spring依靠这个判断解决循环依赖,检测循环依赖
* 是这样的,当发现有依赖循环时,比如A依赖B,B依赖A,此时获取A的Bean
* Spring发现依赖循环,并且B的Bean还没有被创建,先创建A的ObjectFactory,然后添加进singletonFactories
* 在下面的populateBean方法,将属性的依赖B创建
*/
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 这里有三个条件需要判断:1、是否为代理;2、是否允许允许循环依赖;3、是否对应的Bean正在创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 为避免后期循环依赖,可以在Bean初始化完成前将创建实例的ObjectFactory加入工厂
// 在Lambda表达式中,我们熟知的AOP的advice就是在这里动态织入的
// addSingletonFactory方法就是将ObjectFactory放进singletonFactories中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean) );
}

在创建Bean的时候会判断这个Bean是否存在循环依赖,此时TestA会判断出存在循环依赖。就会执行 addSingletonFactory
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory

1
2
3
4
5
6
7
8
9
10
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);
}
}
}

也就是为A封装一个ObjectFactory并添加进singletonFactories,为了给下面循环依赖的B使用
接下来解析A的属性时发现依赖B的Bean,因为B的Bean还没被创建,所以需要创建B,所以又走了一遍上面的流程。当解析B的属性时发现依赖A的Bean,因为A的Bean还没有,所以先获取A的Bean,所以会执行这段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先尝试从IOC容器中获取Bean
Object singletonObject = this.singletonObjects.get(beanName);
// 如果获取不到Bean,并且解析出当前Bean存在循环依赖
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 尝试从earlySingletonObjects中获取Bean
// earlySingletonObjects跟singletonFactories是相辅相成的
// singletonFactories中存放ObjectFactory,ObjectFactory可以返回一个实例
// earlySingletonObjects可以存放ObjectFactory返回的实例
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果不在earlySingletonObjects中
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// 判断是否有ObjectFactory,如果有,就通过ObjectFactory创建
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 将实例存放进earlySingletonObjects
this.earlySingletonObjects.put(beanName, singletonObject);
// 将ObjectFactory移除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}

因为singletoeFactories中有两个ObjectFactory分别是A和B的,所以使用A的ObjectFactory提供的实例为B中的A赋值,当B创建完后又将B的Bean赋值给A中的B,这样A的Bean也就创建完成了。

*注意:循环依赖只运行单例,原型直接抛出异常

画图理解