Spring如何处理循环引用

循环引用举例

@Component("beanA")
public class BeanA {
    @Autowired
    private BeanB beanB;
}
@Component("beanB")
public class BeanB {
    @Autowired
    private BeanA beanA;
}

以上就是典型的循环引用场景。

熟悉Spring的人都知道Spring是通过三级缓存来处理循环依赖:

/** Cache of singleton objects: bean name --> bean instance */
// 一级缓存 Spring容器中所有的单例bean,这也是狭义的IOC容器
private final Map singletonObjects = new ConcurrentHashMap(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
// 三级缓存
private final Map> singletonFactories = new HashMap>(16);
/** Cache of early singleton objects: bean name --> bean instance */
// 二级缓存
private final Map earlySingletonObjects = new HashMap(16);

下面是本次跟踪的大概流程,主要是关注了三级缓存的变化情况

一张省略了很多的循环引用处理流程图

用大白话来描述一下流程(假定beanA先创建):

Code1:
从Spring真正开始创建对象的doGetBean方法开始

protected  T doGetBean(final String name, @Nullable final Class requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) 
            throws BeansException {

    final String beanName = transformedBeanName(name);
    Object bean;
    // 尝试从一、二、三级缓存中获取beanA,跳到Code2
    Object sharedInstance = getSingleton(beanName);
    //  省略 ....     
    if (mbd.isSingleton()) {
        // Code1.1 由于上面获取不到beanA,此处开始创建beanA,跳到Code3
        sharedInstance = getSingleton(beanName, () -> {
            try {
                return createBean(beanName, mbd, args);
            } catch (BeansException ex) {
                destroySingleton(beanName);
                throw ex;
            }
    }
    //  省略 ....
    return (T) bean;
}

Code2:
此时,由于beanA第一次被创建,因此一级缓存获取不到对象,返回NULL,再次返回Code1创建beanA

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从一级缓存中获取beanA,此时是获取不到的
    Object singletonObject = this.singletonObjects.get(beanName);
    // 由于beanA不是正在创建的对象,因此if判断进不去,不会尝试去二、三级缓存加载bean
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
       // 省略 ...
    }
    return singletonObject;  // 返回null 跳回Code1.1
}

Code3:(注意这里重载了Code2的方法)
首先从一级缓存中尝试获取beanA,如果获取不到则标记当前beanA处于创建状态,通过ObjectFactory开始创建beanA

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
    synchronized (this.singletonObjects) {
        // 从一级缓存获取bean
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // 省略 ...
            // 这里标记beanA已经开始创建
            beforeSingletonCreation(beanName);
            // 省略 ...
            try {
                // 通过ObjectFactory创建对象 跳向Code4
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            } finally {
                // 省略 ...
                // 将beanA从正在创建的集合中移除
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
               // 将beanA从二级缓存earlySingletonObjects中移除
               // 添加到一级缓存singletonObjects
               // 这个方法会统一将二三级缓存挪动到一级缓存
               addSingleton(beanName, singletonObject);
            }
    }
    return singletonObject;   // 到此一个循环引用的对象创建成功返回 END
}

Code4:
首先通过推断出来的构造器创建beanA,接着将beanA放入三级缓存,开始为beanA填充属性,此时会发现beanB尚未创建,进入beanB的创建流程

beanA填充beanB属性完毕,从一、二级缓存中尝试获取缓存中的beanA

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, 
        final @Nullable Object[] args) throws BeanCreationException {

    // 此处通过构造器反射创建Bean对象,
    // 到此beanA已经创建出来,但是没有属性填充
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();

    // 判断是否可以当前被创建的对象是否可以提前暴露
    // 条件:单例对象、正在被创建、允许循环引用
    boolean earlySingletonExposure = (mbd.isSingleton() 
                                    && this.allowCircularReferences 
                                    && isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        // 在这里将beanA放入到了三级缓存singletonFactories中
        addSingletonFactory(beanName, 
                () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    Object exposedObject = bean;
    try {
        // 此处beanA已经创建成功,开始填充beanA的属性beanB,
        // 创建beanB和beanA的逻辑差不多,跳到 Code5
        populateBean(beanName, mbd, instanceWrapper);   
        // 填充完bean对象的属性,开始执行初始化操作
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable ex) {
        // 省略
    }
    // Code4.1 这里的if判断会进去,此时beanA已经填充了beanB
    if (earlySingletonExposure) {
        // 重新从一、二级缓存中获取beanA 跳到Code9
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            // 省略 ...
        }
    }
    // 省略 ...
    return exposedObject;  // Code4.2 返回创建成功的beanA,返回Code3.1处
}

Code5:
创建beanB的流程其实类似上面创建beanA的流程,首先在一、二、三级缓存中没有找到beanB,则开始创建beanB

protected  T doGetBean(final String name, @Nullable final Class requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) 
        throws BeansException {

    final String beanName = transformedBeanName(name);
    Object bean;

    // 尝试从一、二、三级缓存获取beanB,就是Code2的逻辑,
    // 此时是获取不到beanB的
    Object sharedInstance = getSingleton(beanName);
     //  省略 ....        
    // Create bean instance.
    if (mbd.isSingleton()) {
       // 由于上面获取不到beanB,此处开始创建beanB,跳到Code6
        sharedInstance = getSingleton(beanName, () -> {
            try {
                return createBean(beanName, mbd, args);
            } catch (BeansException ex) {
                destroySingleton(beanName);
                throw ex;
           }
    }
    //  省略 ....
    return (T) bean;
}

Code6:
这个其实就上面创建beanA的时候执行过得Code2,先从一级缓存获取beanB,没有获取到则标记beanB正在创建,进入创建beanB的流程

beanB经历实例化、属性填充、初始化操作之后,清除beanB正在创建标记,并将beanB从三级缓存挪到一级缓存

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
    synchronized (this.singletonObjects) {
        // 从一级缓存获取beanB
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // 省略 ...
            // 这里标记beanB已经开始创建
            beforeSingletonCreation(beanName);
            // 省略 ...
            try {
                // 利用ObjectFactory创建beanB对象,跟Code4一样,
                // 将beanB放入三级缓存singletonFactories,
                // 并且开始尝试获取beanA注入beanB,跳向Code7
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }  finally {
                // 省略 ...
                // Code6.1 将beanB从装在创建的集合中移除
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                // 将beanB从三级缓存singletonFactories中移除,
                // 加入到一级缓存singletonObjects
                // 这个方法会统一将二三级缓存挪动到一级缓存
                addSingleton(beanName, singletonObject);
            }
        }
        // 返回创建完毕的beanB给beanA 返回Code4.1处
        return singletonObject;   
    }
}

Code7:
这里与创建beanA过程的Code4一样,创建beanB完毕之后,开始为beanB填充属性beanA

为beanB填充完毕beanA,beanB的创建过程主要步骤(实例化、属性填充、初始化)结束

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, 
        final @Nullable Object[] args) throws BeanCreationException {

    // 省略beanB对象的创建过程...

    // 在这里将beanB放入到了三级缓存singletonFactories中
    boolean earlySingletonExposure = (mbd.isSingleton() 
                                    && this.allowCircularReferences 
                                    && isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        addSingletonFactory(beanName, 
                () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    Object exposedObject = bean;
    try {
        // 此处beanB已经创建成功,开始填充beanB的属性beanA,跳到 Code8
        populateBean(beanName, mbd, instanceWrapper);
        exposedObject = initializeBean(beanName, exposedObject, mbd); 
    } catch (Throwable ex) {
        // 省略
    }
    // 省略 ...
    // Code 7.1  beanB成功装配了beanA属性,beanB创建过程完毕,
    // 返回Code6.1处
    return exposedObject;
}

Code8:
为beanB填充属性beanA的时候,Spring再次尝试创建beanA,此时会走到Code1的流程,但是此时Spring已经可以从三级缓存中获取到beanA,因此不会再往下执行beanA的创建,同时会将beanA从三级缓存移动到二级缓存

PS.
经过beanA和beanB的创建,我们发现Spring每次创建一个bean都会尝试先去一、二、三级缓存获取,这里其实就是Code2中getSingleton,如果一级缓存没有获取到,但是bean正在被创建则尝试去二级缓存获取,二级缓存没有获取到,但是bean允许提前引用则再次尝试从三级缓存获取

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从一级缓存中获取beanA,此时是获取不到的
    Object singletonObject = this.singletonObjects.get(beanName);
    // 此时beanA已经被标记为正在创建的对象,因此这次if判断可以进去
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 此时二级缓存中不存在beanA
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 此处allowEarlyReference为true,因此这个if判断会进去
            if (singletonObject == null && allowEarlyReference) {
                // 从三级缓存中获取到beanA
                ObjectFactory singletonFactory 
                        = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 将beanA从三级缓存中移除,加入到二级缓存
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    // 从三级缓存中获取到beanA,此时beanB就能正常的获取到beanA进行装配,
    // 返回到Code7的Code7.1处
    return singletonObject;  
}

Code9:
beanA经历创建、属性填充、初始化完毕,重新尝试从缓存中获取

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从一级缓存中获取beanA,此时是获取不到的
    Object singletonObject = this.singletonObjects.get(beanName);
    // 此时beanA已经被标记为正在创建的对象,因此这次if判断可以进去
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 从二级缓存中获取到beanA
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 此处allowEarlyReference为false,因此这个if判断进不去
            if (singletonObject == null && allowEarlyReference) {
                // 省略 ...
            }
        }
    }
    return singletonObject;  // 返回beanA 回到Code4.2处
}
Spring为什么要使用三级缓存来解决循环依赖,而不使用二级缓存?

从上面解决循环引用的问题,我们可以总结出,Spring创建对象、装配属性的时候都尝试先从一、二、三级缓存加载创建好的对象,在装配属性的时候如果从三级缓存获取到对象,会移动到二级缓存,此后获取这个对象就会先从二级缓存中获取。

如果采用二级缓存,单纯从解决循环引用的角度来说确实可以实现,就以上面的beanA来说,假设beanB通过二级缓存装配了beanA属性,后续beanA被某些操作重新包装了一次再次放入二级缓存,就会导致同一个beanA属性,在不同的bean中引用了不同的对象。

你可能感兴趣的:(Spring如何处理循环引用)