1. Spring解决循环依赖问题
一、前面的知识
1. 什么是循环依赖?
- 循环依赖就是循环引用,指两个或多个bean互相持有对方。
- 通常来说,如果问Spring内部如何解决循环依赖,一定是默认的单例Bean中,属性互相引用的场景
- 原型(Prototype)的场景是不支持循环依赖的,存在循环依赖会抛出异常
- 原因很好理解,创建新的A时,发现要注入原型字段B,又创建新的B发现要注入原型字段A...
- 构造器循环依赖会抛出异常
- 通常来说,如果问Spring内部如何解决循环依赖,一定是默认的单例Bean中通过 @Autowired或者 setter方法进行循环依赖
2. 原始对象、代理对象
(1)未使用 AOP时,Spring管理的是原始对象
(2) 使用 AOP 时
-
AOP 生成一个代理对象,内部有一个target属性指向原始对象。
-
Spring并没有给代理对象进行属性填充。只是给原始对象进行了属性填充。放入单例池中的,肯定是一个代理对象。所以注入的属性也是代理对象
3. Spring 的AOP中步骤,
-
- 实例化对象
- new 一个代理工厂
- 把对象设置到工厂中去
- 给工厂设置一些代理的逻辑
- 获取一个代理对象
- 执行代理对象的方法
二、Spring 循环依赖问题分析
1 (1). AService的Bean生命周期
- 实例化出来一个对象(new AService())
- 填充bService属性 (去单例池查找BService对象-->没有找到-->创建BService对象)
- 填充其他属性
- AOP
- 把对象放入单例池
(2). BService的Bean生命周期
- 实例化出来一个对象(new BService())
- 填充aService属性 ( 去单例池查找AService对象-->没有找到-->创建AService对象)
- 填充其他属性
- AOP
- 把对象放入单例池
2 (1). AService的Bean生命周期
- 实例化出来一个对象(new AService() --》 原始对象 --》TempMap<aService: 原始对象> )
- 填充bService属性 ( 去单例池查找BService对象-->没有找到-->创建BService对象)
- 填充其他属性
- AOP
- 把对象放入单例池
(2). BService的Bean生命周期
-
实例化出来一个对象(new BService())
-
填充aService属性 (去单例池查找AService对象 --》没有找到 --》去TempMap查找 --》获得AService原始对象)
-
填充其他属性
-
AOP
-
把对象放入单例池
存在的问题:
- bService填充aService属性时,从tempMap中拿出来的是一个原始对象。而最终放入单例池中的是一个代理对象,最终填充aService属性的也需要是代理对象。
如何判断对象是否出现了循环依赖?
上式BService去单例池查找AService对象,没有找到。即可知AService出现了循环依赖,因为AService创建过程中才导致BService进行创建,而BService创建时发现AService自己还在创建过程中。
3(1). AService的Bean生命周期
-
creatingSet.add("aService")
-
实例化出来一个对象(new AService() --》原始对象 --》TempMap<aService: 原始对象> )
-
填充bService属性 ( 去单例池查找BService对象-->没有找到-->创建BService对象)
-
填充其他属性
-
AOP
-
把对象放入单例池
-
creatingSet.remove("aService")
(2). BService的Bean生命周期
- 实例化出来一个对象(new BService())
- 填充aService属性 (去单例池查找AService对象 --》没有找到,且AService正在创建中 --》去TempMap查找得到AService原始对象 --》对AService进行AOP--》获得AService代理对象)
- 填充其他属性
- AOP
- 把对象放入单例池
(3). CService的Bean生命周期
- 实例化出来一个对象(new CService())
- 填充aService属性 (去单例池查找AService对象 --》没有找到,且AService正在创建中 --》去TempMap查找得到AService原始对象 --》对AService进行AOP--》获得AService代理对象)
- 填充其他属性
- AOP
- 把对象放入单例池
存在问题
- 原始对象属性还未填充,即代理对象还不完整。所以 (2)的第二步不能将AService对象放入单例池中,且 AService其他属性填充也会创建 BService对象。
- AService存在CService属性时,又会创建一个AService代理对象
总结: 所以,依赖的对象存在于creatingSet即表示此对象存在循环依赖
4(1). AService的Bean生命周期
-
creatingSet.add("aService")
-
实例化出来一个对象(new AService() --》原始对象 --》TempMap<aService: 原始对象> )
-
填充bService属性 ( 去单例池查找BService对象-->没有找到-->创建BService对象)
-
填充其他属性
-
AOP
4.1从第二级缓存Map中取得AService代理对象
-
把对象放入单例池
-
creatingSet.remove("aService")
(2). BService的Bean生命周期
- 实例化出来一个对象(new BService())
- 填充aService属性 (去单例池查找AService对象 --》 没有 --》从二级缓存进行查找 --》没有找到,且AService正在创建中 --》去TempMap查找得到AService原始对象 --》对AService进行AOP--》获得AService代理对象 --》代理对象放入第二级缓存Map )
- 填充其他属性
- AOP
- 把对象放入单例池
(3). CService的Bean生命周期
- 实例化出来一个对象(new CService())
- 填充aService属性 (去单例池查找AService对象 --》 没找到,去二级缓存中查找--》获得AService代理对象 )
- 填充其他属性
- AOP
- 把对象放入单例池
总结:
- 二级缓存,保证了提前进行AOP的代理对象是唯一的。
- 步骤(2)中,执行 TempMap中的 lambda表达式就是进行 AOP 操作。定义AService时候, lambda还是 AService生命周期内,可以多存储参数。
- 第一级缓存: 单例池
- 第二级缓存: Map(beanName,不完整的代理对象)
- 第三级缓存:TempMap(beanName,原始对象)
三、Spring循环依赖处理流程
1 (1). AService的Bean生命周期
-
creatingSet.add("aService")
-
实例化出来一个对象(new AService() --》原始对象 --》singletonFactories<aService: lambda(原始对象)> )
-
填充bService属性 ( 去单例池查找BService对象-->没有找到-->创建BService对象)
-
填充其他属性
-
AOP(判断是否存在AService代理对象?)
4.1从第二级缓存Map中取得AService代理对象
-
把对象放入单例池
-
creatingSet.remove("aService")
(2). BService的Bean生命周期
- 实例化出来一个对象(new BService())
- 填充aService属性 (去单例池查找AService对象 --》 没有 --》从二级缓存进行查找 --》没有找到,且AService正在创建中 --》去singletonFactories查找得到lambda(AService原始对象) --》执行lambda进行AOP--》获得AService代理对象 --》代理对象放入第二级缓存Map )
- 填充其他属性
- AOP
- 把对象放入单例池
2. 三个缓存源码定义 。
源码中的方法:getSingleton(String beanName, boolean allowEarlyReference)
第一级缓存: 单例池 singletonObject = new HashMap(beanName: Bean完整的代理对象)
第二级缓存: earlySingletonObject = new HashMap(beanName: Bean不完整的代理对象)
第三级缓存 :singletonFactories = Map(beanName, lambda(原始对象)) 。
3. 流程图

四、问题解答
- 源码中加synchronized锁的意义?
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 1. 执行lambda表达式,进行AOP,得到代理对象
singletonObject = singletonFactory.getObject();
// 2. 代理对象放入2级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 3. 3级缓存中移除此对象
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
背景:
二级缓存中的aService对象是三级缓存中的lambda表达式生成出来的,
他们是成对的,二级缓存中存在代理对象,则三级缓存中不应该存在lambda表达式;
或者说,三级缓存中存在lambda表达式,则二级缓存中不应当有该代理对象
解答:
-
3级缓存中的 value是一个lambda表达式,一执行就是进行AOP,得到代理对象,所以lambda表达式应当只执行一次,且执行完毕后从3级缓存中进行移除,以防止其他的代码又拿出来执行了
-
在第2、第3级缓存只能有一个地方存在操作对象,要么是lambda表达式(三级缓存),要么是lambda执行后的代理对象(二级缓存)。这是原子性的,为了对高并发情况进行控制,加锁进行同步。
-
1级缓存定义为 concurrentHashMap。 2级、3级缓存定义为简单的HashMap,是因为 2、3级缓存是成对出现的,哪怕是定义成concurrentHashMap,也要加锁保持两个Map的操作的原子性
2. AService第4步, 如何判断是否存在AService代理对象?
答: 从二级缓存中进行查找AService代理对象。 可行,但是 AOP可以看做是一种插件,缓存是一个bean工厂。这两个是相互独立的,要互相解耦,所以Spring不是直接这么做的
上式AService,存在循环依赖,所以步骤2(具体为注入bService属性过程中)会执行lambda表达式,即执行了getEarlyBeanReference(Object bean, String beanName) 方法, 提前获取代理对象步骤4会执行postProcessAfterInitialization(),根据返回的是原始对象还是代理对象,再从二级缓存进行拿取
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName); // 获取beanName, aService
// lambda表达式执行时,AOP执行前的原始对象存入earlyProxyReferences Map中
this.earlyProxyReferences.put(cacheKey, bean);
// 真正进行 AOP
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// earlyProxyReferences 存的是提前进行了AOP的bean, beanName:AOP之前的对象
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
// 实际创建对象
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
// 1. 初始化
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// 2. 实例化
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//原始对象
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 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) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 此时的bean还没有完成属性注入,是一个非常简单的对象
// 构造一个对象工厂,添加到singletonFactory中
// TODO: 执行到这一行时, lambda表达式并未执行, lambda表达式可以记录原始对象的一些属性
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
// 对象已经暴露出去了
Object exposedObject = bean;
try {
// 3. 填充属性 @Autowired
populateBean(beanName, mbd, instanceWrapper);
// 4. 初始化并执行 BeanPostProcessor
// 如果进行了AOP,则返回的exposedObject是代理对象。如果没进行AOP,则返回的是原始对象
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
// 解决循环依赖时,当 AService属性注入完毕后,从 getSingleton中获取 AService进行AOP之后的代理对象
// getSingleton: 从二级缓存中取对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
// 如果提前暴露的对象和经过了完整生命周期的对象相等,则把代理对象赋值给exposedObject
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 如果提前暴露的对象和经过了完整生命周期的对象不相等。
// allowRawInjectionDespiteWrapping 表示处于循环依赖过程中
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}

浙公网安备 33010602011771号