Spring源碼解析之循環(huán)依賴

什么是循環(huán)依賴

簡單的說就是A依賴B,B依賴C,C依賴A這樣就構(gòu)成了循環(huán)依賴


循環(huán)依賴

循環(huán)依賴分為構(gòu)造器依賴和屬性依賴,眾所周知的是Spring能夠解決屬性的循環(huán)依賴(set注入)。下文將從源碼角度分析Spring是如何解決屬性的循環(huán)依賴。

如下配置會產(chǎn)生循環(huán)依賴

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="person" class="com.yao.bean.Person">
        <property name="cat" ref="cat"></property>
    </bean>
    <bean id="cat" class="com.yao.bean.Cat">
        <property name="person" ref="person"></property>
    </bean>
</beans>
    @Test
    public void testAbc() throws IOException {
        BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        //獲取bean的時候就會涉及到循環(huán)依賴的處理
        Person person = (Person) bf.getBean("person");
        person.say();
    }

我們跟進源碼可以看到如下代碼

protected <T> T doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException {
        //修正名稱
        String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        //從單例緩存中獲取bean,這里就涉及到spring的1,2,3級緩存,第一次獲取的時候sharedInstance 肯定為空
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isTraceEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            // 對于scope==prototype的,如果出現(xiàn)循環(huán)依賴,則直接拋異常,無法處理
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            ......
            if (!typeCheckOnly) {
                //標記當(dāng)前bean正在創(chuàng)建,就是將當(dāng)前的beanName放到Set集合中,后面會作為其中一個判斷條件去判斷是否去從1或者2或者3級緩存中獲取bean
                markBeanAsCreated(beanName);
            }

            try {
                ......
                // Create bean instance.
                //創(chuàng)建bean實力的邏輯,
                if (mbd.isSingleton()) {
//獲取beanName的實力
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            ......
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
        ......
        return (T) bean;

查看public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)如下

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        
        synchronized (this.singletonObjects) {
            //從一級緩存中獲取bean
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                ...
                try {
                    /**
                     * 這里singletonFactory.getObject()實際是上一步中的匿名內(nèi)部類的方法,即try中的語句塊
                     * sharedInstance = getSingleton(beanName, () -> {
                     *                      try {
                     *                          return createBean(beanName, mbd, args);
                     *                   }...)
                     */
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                ...
            return singletonObject;
        }
    }

我們可以繼續(xù)返回上一步中繼續(xù)查看return createBean(beanName, mbd, args);邏輯

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

        ...
        try {
            //這里是真正創(chuàng)建bean的邏輯,真正處理的邏輯一般都是doXXXX,do開頭的
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        ...
    }

繼續(xù)查看doCreateBean()邏輯
這一步第一次將A放入了三級緩存,這個時候A實例化,但是未初始化。

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

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            //這里最終會使用jdk的類加載器去去實例化當(dāng)前bean,僅僅只是newInstance,
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
       // ......
        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        //緩存單例用于接續(xù)循環(huán)依賴,
        //(單例 && 允許循環(huán)依賴(此處是恒定值,但是可以利用別的BeanFactory實現(xiàn)去改寫這個值) && 當(dāng)前bean是否處于正在創(chuàng)建中)
        //這里為true,進入if,
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            //添加到三級緩存,但是這時候bean還未實例化,下次別的Bean依賴的時候在調(diào)用真正的邏輯(匿名內(nèi)部類)
            //這里的匿名內(nèi)部類意思是: 提前將實例化的bean暴露出去,記住,僅僅是實例化,沒有初始化
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            //填充屬性,這個時候發(fā)現(xiàn)屬性A類中的B屬性未實例化,則實例化B,實例化B之后,則把把B的屬性填充給A,這個時候填充
            //的時候回從三級緩存中獲取Bean
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
            //......
        return exposedObject;
    }

繼續(xù)查看填充屬性的邏輯AbstractAutowireCapableBeanFactory.java

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        //......
        //這里去發(fā)現(xiàn)當(dāng)前bean需要填充的屬性,也就是需要依賴的對象屬性,這個時候如果pvc肯定不為空,繼續(xù)進入下面if語句
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
              //......
        if (pvs != null) {
            //將依賴的屬性賦值到當(dāng)前bean中
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }

查看applyPropertyValues
AbstractAutowireCapableBeanFactory.java

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        if (pvs.isEmpty()) {
            return;
        }

        if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
            ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
        }

        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;

        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            if (mpvs.isConverted()) {
                // Shortcut: use the pre-converted values as-is.
                try {
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
                }
            }
            //獲取需要填充的屬性名稱s
            original = mpvs.getPropertyValueList();
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

        // Create a deep copy, resolving any references for values.
        List<PropertyValue> deepCopy = new ArrayList<>(original.size());
        boolean resolveNecessary = false;

        //循環(huán)去填充所有的屬性值
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            else {
                //依賴的屬性名稱
                String propertyName = pv.getName();
                //依賴的屬性值,第一次這個值的類型是 RuntimeBeanReference
                Object originalValue = pv.getValue();
                //解析屬性,里面的邏輯會進入RuntimeBeanReference判斷邏輯,進行屬性的解析
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
                }
                // Possibly store converted value in merged bean definition,
                // in order to avoid re-conversion for every created bean instance.
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // Set our (possibly massaged) deep copy.
        try {
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
    }

繼續(xù)查看valueResolver.resolveValueIfNecessary()

@Nullable
    public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
        // We must check each value to see whether it requires a runtime reference
        // to another bean to be resolved.
        //上一步說的那個屬性值是RuntimeBeanReference,這里判斷一下為true,那就繼續(xù)解析屬性
        if (value instanceof RuntimeBeanReference) {
            RuntimeBeanReference ref = (RuntimeBeanReference) value;
            //繼續(xù)解析依賴的屬性。
            return resolveReference(argName, ref);
        }
         //...

繼續(xù)查看resolveReference()方法可以看到準備在factory中解析依賴的bean

/**
     * Resolve a reference to another bean in the factory.
     * 在factory中解析對另一個bean的引用
     */
    @Nullable
    private Object resolveReference(Object argName, RuntimeBeanReference ref) {
        try {
            //...
            }
            else {
                //這里會從factory中獲取引用的bean,第一次循環(huán)完畢。里面會重頭進入doGetBean()相關(guān)方法,然后一步步會獲取引用的bean.
                bean = this.beanFactory.getBean(refName);
                this.beanFactory.registerDependentBean(refName, this.beanName);
            }
            //...
            return bean;
        }
        //...
    }

至此在初始化A的時候(只是實例化為初始化)的過程中,發(fā)現(xiàn)需要依賴B,那么這個時候再去factory中去找B,接下來我們發(fā)現(xiàn)B走了同樣的流程,然后繼續(xù)初始化A,此時狀態(tài)如下:


image.png

程序?qū)嵗盟械腷ean之后,第二輪開始進行依賴bean的set值,我們會看到剛開頭的代碼

protected <T> T doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException {
        //修正名稱
        String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        //從單例緩存中獲取bean,這里就涉及到spring的1,2,3級緩存
        Object sharedInstance = getSingleton(beanName);
        //...

繼續(xù)查看getSingleton(beanName);

@Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        //第二輪進入的時候isSingletonCurrentlyInCreation(beanName)為true,進入if,每一次第一次初始化的bean的時候,都會
        //標識此bean正在創(chuàng)建中。
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                //從二級緩存獲取,此時為null,allowEarlyReference默認一直true
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    //從3級緩存獲取之前存儲的匿名內(nèi)部類
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        //調(diào)用匿名內(nèi)部類的方法去執(zhí)行doCreateBean的創(chuàng)建
                        singletonObject = singletonFactory.getObject();
                        //將當(dāng)前實例化好,但是未初始化的A放入二級緩存
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        //把當(dāng)前在三級緩存中存放的beanName移除掉
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

此時A,B在緩存中的狀態(tài)為:


image.png

接著會將這個A會暴露出去,讓B去完成A屬性的賦值,這個時候我們可以繼續(xù)查看初始化B的階段中給A屬性賦值的邏輯

@Nullable
    private Object resolveReference(Object argName, RuntimeBeanReference ref) {
        try {
                    //...
            else {
                //這個時候從factory中拿到了已經(jīng)實例化好的A
                bean = this.beanFactory.getBean(refName);
                this.beanFactory.registerDependentBean(refName, this.beanName);
            }
            
            return bean;
        //...
    }

賦值操作

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        //...
        //循環(huán)去填充所有的屬性值
        for (PropertyValue pv : original) {
            //...
            else {
                //依賴的屬性名稱
                String propertyName = pv.getName();
                //依賴的屬性值,第一次這個值的類型是 RuntimeBeanReference
                Object originalValue = pv.getValue();
                //解析屬性,里面的邏輯會進入RuntimeBeanReference判斷邏輯,進行屬性的解析
                //這個時候已經(jīng)解析到A屬性的Bean了,接下來就是把A 賦值給B bean即可完成B的實例化初始化
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                Object convertedValue = resolvedValue;
                //...
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        //...
        // Set our (possibly massaged) deep copy.
        try {
            //這里就是賦值操作
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
//...
    }

一步步往下跟,我們可以看到如下代碼

protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            //將B放入一級緩存
            this.singletonObjects.put(beanName, singletonObject);
            //將B從三級緩存移除
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }

此時A,B在1,2,3級緩存中的狀態(tài)如下:


image.png

此時B已經(jīng)完全的實例化并初始化完畢,可以正常的使用了。接下來就是繼續(xù)完成A中B屬性的賦值即可
剩下的邏輯我就不分析了。
A,B在1,2,3級緩存中的狀態(tài)變化如下:


spring 三級緩存解決循環(huán)依賴狀態(tài)圖.png

至此spring如何解決循環(huán)依賴已經(jīng)分析完畢。但是我們需要思考以下幾個問題

只有一級緩存能否解決循環(huán)依賴?

只有一級是解決不了的,一級緩沖中到時候存放的bean你是不知道到底是不是初始化完畢的。

只有二級能否解決循環(huán)依賴?

參考文章:https://www.bilibili.com/read/cv6674250

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

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