0%

Spring循环依赖三级缓存解析

Spring循环依赖三级缓存解析。

Spring循环依赖使用场景

  1. 对象A的构造方法中依赖了B的实例对象, 同时B的field或者setter需要A的实例对象
  2. 对象A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象
    (不能解决的使用场景) 3. 对象A的构造函数依赖了B的实例对象,B的构造函数依赖了A的实例对象

Spring单体对象初始化的流程

  • createBeanInstance 实例化,仅仅调用对应的构造方法,没有传入指定的sping.xml
  • populate populateBean 填充属性,对spring.xml指定的property进行populate
  • initializeBean 调用spring.xml中指定的init方法,或者AfterPropertiesSet方法

Spring循环依赖的三级缓存

DefaultSingletonBeanRegistry中的三级缓存:

1
2
3
4
5
6
// 存放初始化好的可以直接使用的bean,单例对象的cache - 一级缓存 
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
// 提前曝光的单例对象cache- 二级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
// 存放单例对象工厂的cache - 三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected Object getSingleton(String beanName, boolean allowEarlyReference) { 
// 从一级缓存中取实例
Object singletonObject = this.singletonObjects.get(beanName);
// 一级缓存中没有,并且对象在创建中(isSingletonCurrentlyInCreation判断对应的单例对象是否在创建中)
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
// 从二级缓存中拿数据
singletonObject = this.earlySingletonObjects.get(beanName);
// 二级缓存中没有并且允许从三级缓存中拿数据(allowEarlyReference是否允许从singletonFactories中拿数据)
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 将三级缓存提到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}

三级缓存的作用

二级缓存的存在有两个作用
1.三级缓存中获取bean,需要循环所有的后置处理器,调用它们实现的方法,效率低下。 2. 为了保护单例对象。三级缓存在使用时,beanA和beanB循环依赖,beanA和beanC循环依赖,从三级缓存中获取beanA需要循环所有的后置处理器,但是程序员可以扩展后置处理器,在实现的方法里面可能重新new了一个bean,这时候返回的就不是spring给我们创建的bean了,这样就导致beanB和beanC注入beanA的时候都在后置处理器中new了一个beanA,这样beanB和beanC中注入的beanA并不是同一个对象,这样就破坏了单例,所以二级缓存存在为了防止破坏单例是必须的。

参考文档: