spring bean循环依赖的探索
创建类进行测试
在spring 里面通常会遇到bean 在创建的时候需要了循环依赖的情况, 例如
a 类里面依赖的b
b类里面依赖的a
这样循环依赖的场景
首先我们来创建2个非常简单的类用来后续的debug探索.
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
debug 分析解决循环的方法
然后就是合适的下端的地方和方式, 可以帮助我们清楚的了解过程
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
//加入断点 ,condition : "a".equalsIgnoreCase(beanName)||"b".equalsIgnoreCase(beanName)
Object sharedInstance = getSingleton(beanName);
//加入断点 ,condition : "a".equalsIgnoreCase(beanName)||"b".equalsIgnoreCase(beanName)
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
//判断是否提前暴露对象, 加入到singletonFactory 里面去,非常重要
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//加入断点 ,condition : "a".equalsIgnoreCase(beanName)||"b".equalsIgnoreCase(beanName)
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
//...
}
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
注入b feild的时候去spring 容器寻找是否有对应的bean
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
//...
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
//获取b , 发现没有就去创建b
beanFactory.getBean(beanName);
分析bean如何完成的创建和注入
-
创建a, 实例化bean , 然后提前暴露自己保存到singletonFactories 里面去, 为后去依赖a的bean的创建做好准备, 这是解决循环依赖的一个重要的点
-
populateBean 方法执行, 开始填充A 里面的属性b, getBean b 发现没有, 那么就创建b, 同样的道理还是实例化B , 然后提前暴露放到三级缓存里面
-
populateBean 方法执行, 开始填充B里面的属性a, getBean a 发现有了, 上面已经提前暴露了a 到三级缓存(singletonFactories)然后三级缓存移除a, 并且放入到二级缓存(earlySingletonObjects 保存的就是earlyBeanReference)
-
然后注入a feild 到 B 的属性里面去, 完成后在将b从三级缓存移除, 放入到了一级缓存,然后实例化b的操作
-
然后注入b feild 到A里面去, 直接从一级缓存就可以获取到了b ,然后将二级缓存的a移除放入到一级缓存里面去, 注入b 后 A就完整了, 然后进行实例化的操作