深入解析Spring容器解決循環(huán)依賴的原理

最近看源碼在研究類似如下配置的循環(huán)依賴是怎么解決的?

<bean id="a" class="com.project.demo.A" scope="singleton">
      <property name="b" ref="b"/>
</bean>
<bean id="b" class="com.project.demo.B" scope="singleton">
      <property name="a" ref="a"/>
</bean>

說明:

1、Spring容器解決循環(huán)依賴的問題配置類必須是單例模式scope="singleton"才支持,如果是scope="prototype"是無法解決循環(huán)依賴的。

2、Spring容器解決循環(huán)依賴主要依靠三級(jí)緩存機(jī)制

2.1 一級(jí)緩存使用的map: private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);

2.2 二級(jí)緩存使用的map: private final Map<String, Object> earlySingletonObjects = new HashMap(16);

2.3 三級(jí)緩存使用的map: private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);

3、Spring容器解決循環(huán)依賴簡(jiǎn)潔概述主要有四大流程方法:獲取對(duì)象 getSingleton()、 創(chuàng)建對(duì)象(實(shí)例化) doCreateBean()、填充屬性(初始化) populateBean()、返回對(duì)象 addSingleton()

在系統(tǒng)啟動(dòng)獲取配置文件后,程序是依次讀取并加載的,所以上面配置文件代碼,先實(shí)例化a對(duì)象,然后初始化a對(duì)象給a添加b屬性,再實(shí)例化b對(duì)象,最后初始化b對(duì)象給添加屬性a.

那么在代碼執(zhí)行過程中,先調(diào)用getSingleton()方法,我們查看源碼

@Nullable
    public Object getSingleton(String beanName) {           // 調(diào)用下方重載方法
        return this.getSingleton(beanName, true);
    }

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {       // 先從一級(jí)緩存中獲取a對(duì)象的實(shí)例
        Object singletonObject = this.singletonObjects.get(beanName);           // 如果從一級(jí)緩存中獲取不到a對(duì)象,那么檢查該對(duì)象是否正在被創(chuàng)建,如果正在被創(chuàng)建,則進(jìn)入if循環(huán)中
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            synchronized(this.singletonObjects) {            // 從二級(jí)緩存中獲取該對(duì)象
                singletonObject = this.earlySingletonObjects.get(beanName);                   // 如果二級(jí)緩存中無法獲取該對(duì)象,那么一定會(huì)進(jìn)入如下if方法,因?yàn)閍llowEarlyReference傳過來的時(shí)候就是true
                if (singletonObject == null && allowEarlyReference) {              // 從三級(jí)緩存中獲取該對(duì)象
                    ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {                           // 如果獲取到了該對(duì)象,就將三級(jí)緩存中的對(duì)象放到二級(jí)緩存中,并且將三級(jí)緩存中的對(duì)象刪除
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }

        return singletonObject;
    }

從三面的源碼發(fā)現(xiàn),如果a第一次獲取,那么第9行的if語句為false,將直接放回為null,這時(shí)回到創(chuàng)建對(duì)象doCreateBean()方法,該方法使用反射的方式生成a對(duì)象,并且該對(duì)象在三級(jí)緩存中,對(duì)象生成后就需要對(duì)a對(duì)象進(jìn)行屬性填充:

 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
         // 省略多行代碼,大致就是調(diào)用各種方法,通過反射創(chuàng)建對(duì)象
         try {
             // a對(duì)象創(chuàng)建完成,調(diào)用屬性填充方法,對(duì)a進(jìn)行屬性填充
             this.populateBean(beanName, mbd, instanceWrapper);
             exposedObject = this.initializeBean(beanName, exposedObject, mbd);
         } catch (Throwable var18) {
             if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                 throw (BeanCreationException)var18;
             }
 
             throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
         }
 
         if (earlySingletonExposure) {
             Object earlySingletonReference = this.getSingleton(beanName, false);
             if (earlySingletonReference != null) {
                 // 省略多行代碼
             }
         }
         // 省略多行代碼
     }

在上面代碼doCreateBean()方法中先創(chuàng)建a對(duì)象,創(chuàng)建完成后會(huì)調(diào)用this.populateBean(beanName, mbd, instanceWrapper)方法對(duì)a進(jìn)行屬性填出,這個(gè)時(shí)候會(huì)獲取配置文件中所有<bean id="a">里面的所有屬性,發(fā)現(xiàn)會(huì)存在一個(gè)b屬性,下面貼出部分源碼

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        if (bw == null) {
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
        } else {
            boolean continueWithPropertyPopulation = true;
            if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
                // 刪除大量代碼
            }

            if (continueWithPropertyPopulation) {
                // 刪除大量源代碼,applyPropertyValues方法中beanName為a,pvs為狀態(tài)各種屬性的PropertyValues對(duì)象,pvs就裝有b這個(gè)屬性
                if (pvs != null) {
                    this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
                }

            }
        }
    }

繼續(xù)跟進(jìn)applyPropertyValues方法的源碼

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        if (!pvs.isEmpty()) {
            if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
                ((BeanWrapperImpl)bw).setSecurityContext(this.getAccessControlContext());
            }
            MutablePropertyValues mpvs = null;
            List original;
            if (pvs instanceof MutablePropertyValues) {
                // 省略大量代碼
            } else {
                original = Arrays.asList(pvs.getPropertyValues());
            }
            // 省略大量代碼 大致過程是將屬性對(duì)象pvs 轉(zhuǎn)化成original List對(duì)象,然后在使用迭代器在下面進(jìn)行迭代
            Iterator var11 = original.iterator();
            while(true) {
                while(var11.hasNext()) {
                    PropertyValue pv = (PropertyValue)var11.next();
                    if (pv.isConverted()) {
                        deepCopy.add(pv);
                    } else {
                        String propertyName = pv.getName();
                        Object originalValue = pv.getValue();
                        // 通過下面方法解決依賴的b,整個(gè)方法在迭代器中,外層在while(true)中,可能有多個(gè)屬性,循環(huán)直到所有屬性都解決了就return;或者拋出異常
                        Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                        // 省略大量代碼
                    }
                }

                if (mpvs != null && !resolveNecessary) {
                    mpvs.setConverted();
                }

                try {
                    bw.setPropertyValues(new MutablePropertyValues(deepCopy));
                    return;
                } catch (BeansException var19) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var19);
                }
            }
        }
    }

繼續(xù)跟進(jìn)上面紅色方法

public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
        if (value instanceof RuntimeBeanReference) {
            RuntimeBeanReference ref = (RuntimeBeanReference)value;
            return this.resolveReference(argName, ref);
        } else if (value instanceof RuntimeBeanNameReference) {
            // 省略多行代碼
        }
        // 省略多行代碼
    }

繼續(xù)跟進(jìn)紅色部分的代碼

private Object resolveReference(Object argName, RuntimeBeanReference ref) {
        try {
            String refName = ref.getBeanName();
            refName = String.valueOf(this.doEvaluate(refName));
            Object bean;
            if (ref.isToParent()) {
                // 省略多行代碼
            } else {
                // 通過refName的值b又去工廠找b對(duì)象
                bean = this.beanFactory.getBean(refName);
                this.beanFactory.registerDependentBean(refName, this.beanName);
            }

            // 省略多行代碼
            return bean;
        } catch (BeansException var5) {
            throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, var5);
        }
    }
public Object getBean(String name) throws BeansException {
         return this.doGetBean(name, (Class)null, (Object[])null, false);
     }
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        String beanName = this.transformedBeanName(name);
        // 跟了這么就,最終表明在實(shí)例化a對(duì)象后,在裝載a的屬性b時(shí),會(huì)經(jīng)過各種校驗(yàn)最終到getSingleton(),及先獲取b對(duì)象,如果b對(duì)象不存在則會(huì)對(duì)b完成創(chuàng)建的過程
        Object sharedInstance = this.getSingleton(beanName);
        // 省略多行代碼
    }

上面整個(gè)過程概括:在檢測(cè)到需要實(shí)例化a時(shí),先去獲取a對(duì)象,看a是否已經(jīng)存在,獲取去先從一級(jí)緩存中獲取,如果沒有并且如果a也沒有正在實(shí)例化,那么直接返回null,表明獲取不到a對(duì)象,那么此時(shí)調(diào)用doCreateBean()方法完成對(duì)a對(duì)象的實(shí)例化過程(通過反射創(chuàng)建a對(duì)象),并且將創(chuàng)建的a對(duì)象放在三級(jí)緩存中,然后繼續(xù)執(zhí)行doCreateBean中的populateBean()方法完成對(duì)a進(jìn)行初始化即添加屬性b,經(jīng)過一些列校驗(yàn),最終又會(huì)調(diào)用getSingleton()方法來獲取b對(duì)象,同樣會(huì)返回null,這個(gè)時(shí)候就會(huì)去執(zhí)行doCreateBean()方法創(chuàng)建b對(duì)象,同樣過反射創(chuàng)建b,當(dāng)b對(duì)象創(chuàng)建完成時(shí)也會(huì)存放在三級(jí)緩存中,在實(shí)例化b對(duì)象完成,然后繼續(xù)執(zhí)行doCreateBean中的populateBean()方法,也需要初始化b對(duì)象,填充b的屬性,這時(shí)發(fā)現(xiàn)b對(duì)象的屬性是a,同樣再次通過getSingleton()方法獲取a,獲取a的過程如第一個(gè)源碼部分,先從一級(jí)緩存中獲取,獲取不到,然后判斷a正在創(chuàng)建中,然后就從二級(jí)、三級(jí)緩存中獲取,最終在三級(jí)緩存中獲取到了a,并且將三級(jí)緩存中的a對(duì)象放到二級(jí)緩存中,并將刪除三級(jí)緩存中的a,此時(shí)b對(duì)象初始化也完成。

在a對(duì)象初始化的流程中,將b對(duì)象也實(shí)例化和初始化了,在b的初始化過程中,將a從三級(jí)緩存移到了二級(jí)緩存中,當(dāng)b初始化完成后繼續(xù)向下執(zhí)行,會(huì)執(zhí)行到addSingleton(),查看源碼

protected void addSingleton(String beanName, Object singletonObject) {
        synchronized(this.singletonObjects) {       // 將b加入到1級(jí)緩存
            this.singletonObjects.put(beanName, singletonObject);            // 將b從三級(jí)緩存中刪除
            this.singletonFactories.remove(beanName);            // 將b從二級(jí)緩存中刪除(b在二級(jí)緩存中沒有,即空刪除)
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }

從上面代碼可以看出在,并創(chuàng)建完成并且初始化后,會(huì)將B從三級(jí)緩存中直接放到一級(jí)緩存中,并且刪除三級(jí)緩存中的數(shù)據(jù)。

所有b工作做完后返回到a初始化屬性b的代碼

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

        // 省略大量代碼
        try {
            // 完成a對(duì)于屬性b的檢查裝配工作后返回到方法populateBean(),繼續(xù)向下執(zhí)行
            this.populateBean(beanName, mbd, instanceWrapper);
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }

        if (earlySingletonExposure) {
            // a執(zhí)行到該方法getSingleton(),這里面會(huì)將a從二級(jí)緩存中取出來
            Object earlySingletonReference = this.getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                // 省略大量代碼
            }
        }
        // 省略大量代碼
    }

繼續(xù)執(zhí)行,最終也會(huì)到addSingleton()方法,將a也加入一級(jí)緩存,并且從二級(jí)緩存中刪除a。

這樣a和b兩個(gè)循環(huán)依賴的bean都被放入到一級(jí)緩存中。


最新2020整理收集的一些高頻面試題(都整理成文檔),有很多干貨,包含mysql,netty,spring,線程,spring cloud、jvm、源碼、算法等詳細(xì)講解,也有詳細(xì)的學(xué)習(xí)規(guī)劃圖,面試題整理等,
需要獲取這些內(nèi)容的朋友請(qǐng)加Q君樣:
11604713672

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容