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中的三级缓存:

// 存放初始化好的可以直接使用的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); 
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并不是同一个对象,这样就破坏了单例,所以二级缓存存在为了防止破坏单例是必须的。

参考文档:

0%