spring 循环依赖问题研究
Posted 子瞻
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring 循环依赖问题研究相关的知识,希望对你有一定的参考价值。
CASE:“A依赖B,同时B又依赖A”。
先贴出来解决循环依赖在DefaultSingletonBeanRegistry中的三个缓存:
//一级缓存
Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//三级缓存
Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//二级缓存
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
分析:
1.A进行create流程,发现自己依赖B,此时B更没有走create流程。
doCreateBean()中有这样的判断是否允许循环依赖,当前bean是否创建中:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
isSingletonCurrentlyInCreation(beanName)的具体实现是:
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
那么它的调用时机又是什么时候呢?
DefaultSingletonBeanRegistry.getSingleton();
AbstractBeanFactory.doGetBean()中也就是AbstractBeanFactory.getBean()调用了上面这个方法.
在这里还有一个调用链路就是:
AbstractApplicationContext.finishBeanFactoryInitialization(beanFactory)->
beanFactory.preInstantiateSingletons()->AbstractBeanFactory.getBean().
在这里,我目前先讨论这两个主要的调用链路,其他的以后再说。
我们接着分析,如果判断出循环引用,则执行addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))。
看一下具体实现:
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
见到了熟悉的singletonFactories,是不是很兴奋呢;此时,A将自己放入到singletonFactories中。
2.发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以B走create流程。
3.B初始化时时候发现自己依赖A,尝试get(A),从singletonObjects(一级缓存)中取,发现没有(此时A还没有初始化完成),earlySingletonObjects(二级缓存)中也没有,最后从singletonFactories(三级缓存)中取,因为在1中A已经存放在singletonFactories里面了,所以B可以拿到A(虽然是个半成品)。
4.此时,B可以顺利完成初始化,并将自己放在singletonObjects中。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
if (this.singletonsCurrentlyInDestruction) {
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
if (newSingleton) {
//添加到singletonObjects中
addSingleton(beanName, singletonObject);
}
}
下面看,具体实现:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
5.此时返回A中,A此时能拿到B,最终A也完成了初始化,进去了一级缓存singletonObjects中。
以上是关于spring 循环依赖问题研究的主要内容,如果未能解决你的问题,请参考以下文章
spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段