Spring默认在 单例、 非构造方法注入的情况下是支持循环依赖的。
准备工作
关闭循环依赖
Spring 提供了关闭循环依赖的方法。
boolean allowCircularReferences
开始调试
我们从 doGetBean
开始分析。
AbstractBeanFactory#doGetBean
Spring 在初始化和 getBean()
时,都会调用这个方法。
源码概览
//...
表示被我省略掉的一些代码
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//...
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//...
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//...
// Create bean instance.
if (mbd.isSingleton()) {
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;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
代码很长,我们节选一些片段来解析
先检查一下单例池当中有没有手动注册的单例对象:
单例池:
Spring 中所有实例化好的单例 Bean 都存放在这个map当中。
判断当前的类是否在正在创建的原型集合当中,如果是,则抛异常:
说明一般情况下,原型不支持循环依赖。
prototypesCurrentlyInCreation:
判断当前 Bean 是否是单例,如果是,则把 Bean 创建出来。
getSingleton(String beanName, ObjectFactory<?> singletonFactory)
分析与循环依赖有关的代码片段:
判断当前实例化的 Bean 是否在正在被销毁:
singletonsCurrentlyInDestruction:
beforeSingletonCreation(beanName):
判断当前 Bean 是否正在被创建。因为 Spring 不管创建 Prototype Bean 还是 Singleton Bean,当他需要正式创建 Bean 的时候他会将这个 Bean add 到一个Set 中去
this.inCreationCheckExclusions.contains(beanName)
判断当前需要创建的 Bean 是否在 Exclusions 集合中,程序员可以提供一些 Bean 不被 Spring 初始化(哪怕被扫描到了,也不初始化),那么这些被提供的 Bean 便会存在这个集合当中;this.singletonsCurrentlyInCreation.add(beanName)
把当前正在创建的 Bean 添加到正在创建的集合中。
singletonsCurrentlyInCreation:
继续往下执行到singletonObject = singletonFactory.getObject();
这里的 singletonFactory 就是上面传进来的那个 Lamda 表达式,我再贴一下:
所以我们要进到 createBean
方法中去。
从调用栈中我们也可以看出来这点:
AbstractAutowireCapableBeanFactory#createBean(beanName, mbd, args)
这里主要是 doCreateBean
方法:
调用 doCreateBean
后,x 和 y 都完成实例化了(循环依赖也完成了):
doCreateBean
下面着重分析一下 doCreateBean
这个方法,上面我们分析过一个名字类似的叫 doGetBean
,别搞混了:
createBeanInstance(beanName, mbd, args)
:
运行完以后,x 的构造方法就被调用了:
但是此时 x 对象只是被创建了,它还不是 Spring Bean,它的生命周期才刚刚开始。
往下执行到 earlySingletonExposure
变量赋值处:
mbd.isSingleton()
我们的 Bean 都是单例的,所以此处为 truethis.allowCircularReferences
默认允许循环依赖,此处为 trueisSingletonCurrentlyInCreation(beanName)
x 在正在创建的 Bean 的集合中,此处为 true
这里又印证了上面我们说的关闭循环依赖的方法。
继续向下执行,这里又是一个 Lamda 表达式:
addSingletonFactory(beanName,singletonFactory)
添加一个单例工厂,这个工厂可以产生我们需要的半成品的 Bean 。
addSingletonFactory
:
下面这几行代码都很重要,依次分析下这几行代码:
先判断单例池 singletonObjects
中是否已经存在这个 Bean ,如果存在说明循环依赖已经完成。这里,我们称 singletonObjects
为一级缓存 。
如果一级缓存中不存在,将工厂对象 put 到 singletonFactories
中去,我们称之为二级缓存。
从 earlySingletonObjects
中移除这个 Bean ,我们称 earlySingletonObjects
为三级缓存。
先记住这三个缓存,我们先往下看,后面再来分析他们。
populateBean
这个方法完成了属性注入:
我们观察一下这行代码执行前后:
执行前:
只实例化了 x,y 还没实例化
执行后:
x 注入 y ,y 也注入了 x ,循环依赖完成!
然后绕来绕去又回到了 getSingleton
:
但是这个 getSingleton
方法是我们上面看到的那个的兄弟(重载):
下面分析下这个兄弟:
- 按照惯例还是先从单例池中获取(一级缓存)x,前面说过获取不到
- 然后判断 x 是否在正在创建Bean 的集合当中,前面分析过这个集合现在存在 x y
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName))
成立进入分支singletonObject = this.earlySingletonObjects.get(beanName);
从三级缓存中获取 x,根据前面的分析三级缓存当中现在什么都没有,故而返回nllif (singletonFactory != null)
成立,进入分支ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
从二级缓存中获取一个 ObjectFactory 工厂对象,二级缓存中存在创建 x 的工厂,故而可以获取到singletonObject = singletonFactory.getObject();
拿到一个半成品的 x Beanthis.earlySingletonObjects.put(beanName, singletonObject);
把 x 放到三级缓存,this.singletonFactories.remove(beanName);
把二级缓存中 x 清除- 二级缓存中只存在一个 y 了,而三级缓存中多了一个 x
总结
最后使用一张图来总结一下
参考资料
转载:https://blog.csdn.net/AlphaBr/article/details/105910792