一 什么是循环依赖
多个bean之间相互依赖,形成了一个闭环。 比如:A依赖于B、B依赖于c、c依赖于A. 通常来说,如果问spring容器内部如何解决循环依赖, 一定是指默认的单例Bean中,属性互相引用的场景。也就是说,Spring的循环依赖,是Spring容器注入时候出现的问题。
如上图所示就是spring的循环依赖过程.
二 如何解决循环依赖
核心: 三级缓存解决循环依赖问题,还有一个辅助当前对象是否创建缓存池
/** Cache of singleton objects: bean name to bean instance. */ 实例单例缓存池
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */ 实例单例工厂池
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */ 实例提前暴露缓存池
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
第一级缓存〈也叫单例池)singletonObjects:存放已经经历了完整生命周期的Bean对象
第二级缓存: earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整)
第三级缓存: Map<String, ObiectFactory<?>> singletonFactories,存放可以生成Bean的工厂
辅助创建池: singletonsCurrentlyInCreation 用来标记当前对象是否正在被创建
2.1 解决循环依赖的流程
- A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B
- B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A
- 然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A
- B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)
- 然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A放到一级缓存中。
2.2 流程图和具体步奏
具体实现细节如上流程图所示
1 | 把A放到当前创建的缓存池 | !this.singletonsCurrentlyInCreation.add(beanName) |
2 | 把A添加到三级缓存 | addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)) |
3 | 把B放到当前创建的缓存池 |
!this.singletonsCurrentlyInCreation.add(beanName) |
4 | 把B添加到三级缓存 | addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)) |
5 | 把A添加到二级缓存 | this.earlySingletonObjects.put(beanName, singletonObject) |
6 | 删除三级缓存中的A 返回A给B赋值 | singletonFactories.remove(A) |
7 | 移除当前创建对象中的B,因为B已经创建完了 | this.singletonsCurrentlyInCreation.remove(B) |
8 | B实例化完成以后放入单例缓存 | this.singletonObjects.put(beanName, singletonObject) |
9 | 移除三级缓存中的B | singletonFactories.remove(B) |
10 | 移除二级缓存中的B | this.earlySingletonObjects.remove(B) |
11 | 移除当前创建对象中的A | this.singletonsCurrentlyInCreation.remove(A) |
12 | A实例化完成以后放入单例缓存 | this.singletonObjects.put(beanName, singletonObject) |
13 | 移除三级缓存中的A | singletonFactories.remove(A) |
14 | 移除二级缓存中的A | this.earlySingletonObjects.remove(A) |
2.3 源码解分析
getBean(dep);
如上代码所示不管是创建A对象还是创建B对象都会调用getBean()方法创建
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
Object sharedInstance = getSingleton(beanName);
@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);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
如上所示 getSingleton(beanName) 每次创建对象都会调用这个方法,那么这个方法做了什么呢?实际上这个方法就是我们Spring解决循环依赖的核心方法.
- 当第一次我们A,B都没有创建的时候,走到这里就会拿不到对象.这样的话就会走创建流程.
- 当A创建依赖去B这个时候创建B,B依赖A 再次走到这里获取A的时候会发现A正在被创建.会走到singletonFactory.getObject()获取三级缓存的创建工厂,完成A的创建.然后把A放入二级缓存,删除三级缓存A的工厂创建方法.
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;
}
});
如上代码所示是创建对象的代码.
beforeSingletonCreation(beanName);
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
如上代码每次创建对象之前都会做个标记判断当前对象是否在创建中.
singletonObject = singletonFactory.getObject();
return createBean(beanName, mbd, args);
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
instanceWrapper = createBeanInstance(beanName, mbd, args);
如上代码所示是创建对象的代码
populateBean(beanName, mbd, instanceWrapper);
for (BeanPostProcessor bp : getBeanPostProcessors()) { //注解版的属性赋值
if (bp instanceof InstantiationAwareBeanPostProcessor) {///AutowiredAnnotationBeanPostProcessor (完成基于注解的自动装配功能)
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);//bean属性 bean实例
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
调用后置处理器给属性赋值
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
getBean(dep);
如上就是给对象赋值的代码.不管是给A自动注入B还是给B自动注入A,都会借助后置处理器给属性赋值,不过最终都会走回到getBean的代码
afterSingletonCreation(beanName);
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
如上代码所示创建完对象以后就会删除标记表示对象已经不在创建中了.
if (newSingleton) {
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);
}
}
如上代码所示表示的是对象创建完以后,会把对象添加到单例缓存池中.并且相应的移除二级缓存和三级缓存.如上就是整个spring解决循环依赖的过程