Spring源码分析—循环依赖处理

循环依赖,其实就是循环引用,就是两个或者两个以上的 bean 互相引用对方,最终形成一个闭环,如 A 依赖 B,B 依赖 C,C 依赖 A。

Spring 循环依赖的场景有两种:

构造器的循环依赖。
field 属性的循环依赖。

对于构造器的循环依赖,Spring 是无法解决的,只能抛出 BeanCurrentlyInCreationException 异常表示循环依赖。Spring 只解决 scope 为 singleton 的循环依赖。对于scope 为 prototype 的 bean ,Spring 无法解决,直接抛出 BeanCurrentlyInCreationException 异常。

getSingleton

spring加载 bean 最初始的方法 AbstractBeanFactory 的 doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) 方法中,首先会根据 beanName 从单例 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
28
29
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从map中获取bean如果不为空直接返回,不再进行初始化工作
Object singletonObject = this.singletonObjects.get(beanName);
// 缓存中的 bean 为空,且当前 bean 正在创建
// isSingletonCurrentlyInCreation(String beanName) 方法:
// 判断当前 singleton bean 是否处于创建中。bean 处于创建中,也就是说 bean 在初始化但是没有完成初始化,核心就在于提前曝光 bean 。
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从 earlySingletonObjects 获取
singletonObject = this.earlySingletonObjects.get(beanName);
// earlySingletonObjects 中没有,且允许提前创建
// allowEarlyReference 是否允许从 singletonFactories 缓存中通过 #getObject() 方法,拿到对象。
// singletonFactories 才是 Spring 解决 singleton bean 的核心。
if (singletonObject == null && allowEarlyReference) {
// 从 singletonFactories 中获取对应的 ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 获得 bean
singletonObject = singletonFactory.getObject();
// 添加 bean 到 earlySingletonObjects 中
this.earlySingletonObjects.put(beanName, singletonObject);
// 从 singletonFactories 中移除对应的 ObjectFactory
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}

这个方法主要是从三个缓存中获取,分别是:singletonObjects、earlySingletonObjects、singletonFactories 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//用于存放完全初始化好的 bean从该缓存中取出的 bean可以直接使用
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/**
* 存放bean工厂对象
*
* 对应关系也是 bean name --> bean instance。
*
* singletonFactories中存放的 bean 不一定是完整的。
*
* bean 在创建过程中就已经加入到 singletonFactories 中了,
* 所以当在 bean 的创建过程中就可以通过 getBean() 方法获取。也是解决循环依赖的关键。
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

//存放的是 ObjectFactory 的映射,原始的bean对象用于解决循环依赖,注意:存到里面的对象还没有被填充属性
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
singletonObjects :单例对象的 Cache 。
singletonFactories : 单例对象工厂的 Cache 。
earlySingletonObjects :提前曝光的单例对象的 Cache 。

第一级为 singletonObjects
第二级为 earlySingletonObjects
第三级为 singletonFactories

流程:

首先,从一级缓存 singletonObjects 获取,没有且当前指定的 beanName 正在创建,就再从二级缓存 earlySingletonObjects 中获取。

如果,还是没有获取到且允许 singletonFactories 通过 #getObject() 获取,则从三级缓存 singletonFactories 获取。如果获取到,则通过其 #getObject() 方法,获取对象,并将其加入到二级缓存 earlySingletonObjects 中,并从三级缓存 singletonFactories 删除。就从三级缓存升级到二级缓存了。

所以,二级缓存存在的意义,就是缓存三级缓存中的 ObjectFactory 的 #getObject() 方法的执行结果,提早曝光的单例 Bean 对象。

缓存中的数据

缓存中的数据从哪里添加进来,在 AbstractAutowireCapableBeanFactory 的 #doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) 方法中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 解决循环依赖问题
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
// Bean 满足三个条件时:
// 单例模式
// 运行循环依赖
// 当前单例 bean 是否正在被创建
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//提前将创建的 bean 实例加入到 singletonFactories 中
//当正在创建A时,A依赖B,此时通过(B将A作为ObjectFactory放入单例工厂中进行early expose,此处B需要引用A,但A正在创建,从单例工厂拿到ObjectFactory,从而允许循环依赖)
//避免后期循环依赖
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

当三级缓存 singletonFactories 和 二级缓存 earlySingletonObjects 中的值都有,在类 DefaultSingletonBeanRegistry 中的addSingleton(String beanName, Object singletonObject) 方法。

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);
}
}

添加至一级缓存,同时从二级、三级缓存中删除。

至此:Spring 在创建 bean 的时候并不是等它完全完成,而是在创建过程中将创建中的 bean 的 ObjectFactory 提前曝光(即加入到 singletonFactories 缓存中)。
这样,一旦下一个 bean 创建的时候需要依赖 bean ,则直接使用 ObjectFactory 的 #getObject() 方法来获取了。