spring bean如何解决循环依赖?
描述一下流程
首先ab两个互相依赖
假设先创建a,设置属性之前 调用了这个方法
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
放入三级缓存,并二级缓存中取出 在设置属性的时候会调用后置处理器 auto 开始注入b
b开始实例华并创建,同样在设置属性的时候调用后置处理器开始注入a
同样的流程 但是在dogetbean开始获取单例的方法时候 发现了三级缓存中存在a了 拿到a返回 直接给他放到二级缓存中就好了 同时清掉三级缓存
这里不同的地方 属性注入时候调用了 return getSingleton(beanName, true); 注意这个值为true 代表了从可以三级缓存中获取这个地方不得不说设计的很精妙
有个大坑 循环依赖的时候会有异步方法的时候 会报错 原因是 调用后置处理器之后发现对象被他们代理过
下面会有个比较元对象是否等于二级缓存中的 但是因为a存在异步 已经被后置处理代理过了 会发现根本不相等
在底下判断的时候又发现a存在被b依赖的现象 就是抛出异常
加入没有存在循环依赖的话 在判断中从getSingleton的时候二级缓存也没有 这时候传入的还是false 并不会去三级缓存中获取,这个时候发现得不到对象 直接return就好了 最后会执行addSingleton 这个时候清掉三级缓存 清掉二级缓存 放入一级缓存中去
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
至此 循环依赖全部解决
解决方案:加@lazy 注意在注入的属性上加
目前公司实现方案:不开启异步,自己实现注解
详细见: Spring是如何利用"三级缓存"巧妙解决Bean的循环依赖问题的
作者:YourBatman