所谓的循环依赖,是指在实例化A类时,注入B类,实例化B类时,注入A类。bash
依赖注入分为构造器注入和字段注入,下面依次对这两种状况分析。ui
@Configuration
@RequiredArgsConstructor
public class Adam {
private final Eve eve;
}
复制代码
@RequiredArgsConstructor
@Configuration
public class Eve {
private final Adam adam;
}
复制代码
AbstractAutowireCapableBeanFactory->createBeanInstance():
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
复制代码
在选择构造器注入的时候,会遍历字段,根据beanClass反推beanName,而后实例化。 一路debug,最终找到了抛出异常的调用栈:this
DefaultSingletonBeanRegistry->getSingleton():
beforeSingletonCreation(beanName);
DefaultSingletonBeanRegistry->beforeSingletonCreation():
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
复制代码
与之对应的是afterSingletonCreation方法spa
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
复制代码
singletonsCurrentlyInCreation是一个Set集合,表示当前正在建立的bean名称,建立完成后,会移除。
原来,当同一个bean未完成实例化,又再一次实例化时,singletonsCurrentlyInCreation.add(beanName)返回false,进而抛出了异常,致使程序报错debug
@Component
public class Adam {
@Autowired
private eve;
}
复制代码
@Component
public class Eve {
@Autowired
private Adam adam;
}
复制代码
这样写发现并无报错,一路debug,发现是这段代码起的做用:code
AbstractBeanFactory->doGetBean():
Object sharedInstance = getSingleton(beanName);
AbstractBeanFactory->getSingleton():
return getSingleton(beanName, true);
AbstractBeanFactory->getSingleton():
// 此时singletonObjects未完成,因此确定是null
Object singletonObject = this.singletonObjects.get(beanName);
// 根据前面的分析,singletonsCurrentlyInCreation确定包含beanName
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
复制代码
此时发现,earlySingletonObjects.get(beanName)
为空,singletonFactories.get(beanName)
获取到了值,继而获取到了singletonObject(这里看出earlySingletonObjects建立,对应的singletonFactory会移除)。从新debug,发现是这里给singletonFactories赋了值:cdn
AbstractAutowireCapableBeanFactory->doCreateBean():
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
DefaultSingletonBeanRegistry->addSingletonFactory():
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
复制代码
这段代码是在实例化完成以后进行的,也就是说,当构造器注入的时候,并无添加到singletonFactories,因此getSingleton(beanName)
返回空,进行了第二次的实例化,从而致使报错(这里看出singletonFactories建立,对应的earlySingletonObjects会移除)。继续debug,最终singletonFactories和earlySingletonObjects都被清除了:blog
DefaultSingletonBeanRegistry->getSingleton():
addSingleton(beanName, singletonObject);
DefaultSingletonBeanRegistry->addSingleton():
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
复制代码
当singletonObjects建立的时候,earlySingletonObjects和singletonFactories的使命就完成了~ci
对于字段注入,IoC容器使用了singletonFactories和earlySingletonObjects来预防循环依赖。rem