Spring 循环依赖
什么是循环依赖
概念: 在代码中对象A依赖对象B,对象B依赖对象A,对象相互之间依赖关系;
Class A{
private B b;
}
Class B{
private A a;
}
Spring能解决什么情况下的依赖
- Spring单例对象的属性之间形成的循环依赖
Class A {
B b ;
private setB(B b){
this.b=b;
}
}
Spring不能解决循环依赖的情况
- 原型的依赖,因为已经委托给容器管理
- 单例的构造器注入;(Spring在refresh()初始化bean对象过程中,需要创建一个Springbean,然后注入其对象)
Spring如何解决的单例的循环依赖问题
三个缓存对象
1:在DefaultSingletonBeanRegistry 单例的注册中心有三个缓存的对象:
- singletonObjects 对象的一级缓存,创建完成后的对象,都在该对象中;
- singletonFactories 单例bean的三级缓存;单例对象工厂的cache,第一次创建的bean单例对象,在第一次创建过程都会现在此缓存一下;
- earlySingletonObjects 提前曝光的单例对象(对象在进行属性注入的时候,获取到singletonFactories中的对象,会将singletonFactories 中的对象,缓存到earlySingletonObjects中去)
2 源码分析
- 先分析获取单例对象时候,先从缓存中拿到单例对象
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//一级缓存
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);//首先判断二级缓存是否存在
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);//判断三级缓存中是否存在bean对象
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();//从三级缓存中取出数据的时候,需要将bean对象转换成器代理对象,
this.earlySingletonObjects.put(beanName, singletonObject);//如果三级缓存中存在,吧bean 对象加入到二级缓存中
this.singletonFactories.remove(beanName);//移除三级缓存中的数据
}
}
}
}
return singletonObject;
}
通过上述代码,非常清晰的告诉读者;在单例的对象创建之前,都会先从一级缓存的singletonObjects获取对象;
如果一级缓存中没有,从earlySingletonObjects 提前曝光的二级缓存中获取对象;
-
在创建bean 开始之前,还会在判断一次缓存中,对象是否存在,从singletonObjects 和 singletonFactories缓存中获取;
/** * Return the (raw) singleton object registered under the given name, * creating and registering a new one if none registered yet. * @param beanName the name of the bean * @param singletonFactory the ObjectFactory to lazily create the singleton * with, if necessary * @return the registered singleton object */ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { //从单例池中取出对象 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { //是否正在销毁,异常 if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } //验证完 要真正开始创建对象,先从标识该bean正在被创建,因为Springbean创建过程复杂,步骤很多,需要标识 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
单例对象在第一次创建的时候,都会将单例对象bean,先放在singletonFactories当中
/** * Add the given singleton factory for building the specified singleton * if necessary. * <p>To be called for eager registration of singletons, e.g. to be able to * resolve circular references. * @param beanName the name of the bean * @param singletonFactory the factory for the singleton object * * */ 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);//加入三级缓存,所以现在singletonFactory, this.earlySingletonObjects.remove(beanName);//并从二级缓存中删除 this.registeredSingletons.add(beanName); } } }
总结:根据上述的源代码,getSingleton和addSingletonFactory ,知道了三个缓存中的转换关系;如果A依赖B,B依赖A
-
A对象第一次创建,先执行getSingleton()方法 bean对象会返回为空,在执行addSingletonFactory(),正在创建的bean会先放在singletonFactories 中
-
因为A依赖B,在处理A的成员变量B的创建过程中,B,也是先执行getSingleton()方法 bean对象会返回为空,在执行addSingletonFactory(),正在创建的bean会先放在singletonFactories 中
-
所以此时 singletonFactories 中存在两个正在创建的bean,A 和B;
-
因为B同样依赖A,B的属性依赖A的对象,在创建的时候,先执行getSingleton(),很清楚的发现
if (singletonFactory != null) { singletonObject = singletonFactory.getObject();//从三级缓存中取出数据的时候,需要将bean对象转换成器代理对象, this.earlySingletonObjects.put(beanName, singletonObject);//如果三级缓存中存在,把bean 对象加入到二级缓存中 this.singletonFactories.remove(beanName);//移除三级缓存中的数据 }
此时对象A从singletonFactory 中取出,并加入到earlySingletonObjects 缓存当中去;并将对象返回;
-
B对象依赖的成员变量A 在创建过程中,在三级缓存中获取得到了对象A,并将其缓存到二级对象earlySingletonObjects中,然后此时回调;B对象先完成创建,并将B对象放在一级缓存(singletonObjects)中
-
B对象,完成initializeBean(aware接口实现,init方法实现,beanpostprocessor实现)完成创建,回溯到A对象中的属性B完成创建
-
A对象的其它属性创建成功,A对象最后从二级缓存中获取到A的对象,放在一级缓存当中
Spring调用栈的时序图
分析spring 解决循环依赖问题,需要主要上面的几个流程,同时把握Spring 源码在初始化Spring bean对象的过程;
- refresh()方法 abstractApplicationContext的方法,bean对象初始化的入口
- finishBeanFactoryInitialization() bean 对象创建的入口方法
- preInstantiateSingletons() ,加载bean对象的RootBeanDefinition,并且开始getBean(),注意bean的动态的代理对象也是再次获取
下面是具体的时序图;有待完善,只记录自己的学习过程
![](https://img.haomeiwen.com/i5294752/e3d380ed65daf096.png)
网友评论