Spring源碼分析(十四)從bean的實例中獲取對象


摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。 

 

在getBean方法中,getObjectForBeanlnstance是個髙頻率使用的方法,無論是從緩存中獲得bean還是根據不同的scope策略加載bean。總之,我們得到bean的實例后要做的第一步就是調用這個方法來檢測一下正確性,其實就是用於檢測當前bean是否是FactoryBean類型的bean,如果是,那么需要調用該bean對應的FactoryBean實例中的getObject()作為返回值。

無論是從緩存中獲取到的bean還是通過不同的scope策略加載的bean都只是最原始的bean狀態,並不一定是我們最終想要的bean。舉個例子,假如我們需要對工廠bean進行處理,那么這里得到的其實是工廠bean的初始狀態,但是我們真正需要的是工廠bean中定義的 factory-method方法中返回的bean,而getObjectForBeanlnstance方法就是完成這個工作的。

/**
 * Get the object for the given bean instance, either the bean
 * instance itself or its created object in case of a FactoryBean.
 * @param beanInstance the shared bean instance
 * @param name name that may include factory dereference prefix
 * @param beanName the canonical bean name
 * @param mbd the merged bean definition
 * @return the object to expose for the bean
 */
protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    // 如果指定的name是工廠相關(以&為前綴)且 beanInstance又不是FactoryBean類型則驗證不通過
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }
    }

    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the
    // caller actually wants a reference to the factory.
    // 現在我們有了個bean的實例,這個實例可能會是正常的bean或者是FactoryBean
    // 如果是FactoryBean我們使用它創建實例,似是如果用戶想要直接獲取工廠實例而不是工廠的getObject方法對應的實例,那么傳人的name應該加入前綴&
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    // 加栽 FactoryBean
    Object object = null;
    if (mbd == null) {
        // 嘗試從緩存中加栽bean
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // Return bean instance from factory.
        //到這里已經明確知道beanInstance—定是FactoryBean類型
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        // containsBeanDefinition檢測beanDefinitionMap中也就是在所有已經加載的類中檢測是否定義beanName
        if (mbd == null && containsBeanDefinition(beanName)) {
            // 將存儲 XML 配置文件的 GenericBeanDefinition 轉換為 RootBeanDefinition, 如果指定beanName是子Bean的話同時會合並父類的相關屬性
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        // 是否是用戶定義的而不是應用程序本身定義的
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

從上面的代碼來看,其實這個方法並沒有什么重要的信息,大多是些輔助代碼以及一些功能性的判斷,而真正的核心代碼卻委托給了getObjectFromFactoryBean,我們來看看 getObjectForBeanlnstance 所做的工作。

(1)對FactoryBean正確性的驗證。

(2)對非FactoryBean不做任何處理。

(3)對bean進行轉換。

(4)將從 Factory 中解析 bean 的工作委托給 getObjectFromFactoryBean。

/**
 * Obtain an object to expose from the given FactoryBean.
 * @param factory the FactoryBean instance
 * @param beanName the name of the bean
 * @param shouldPostProcess whether the bean is subject to post-processing
 * @return the object obtained from the FactoryBean
 * @throws BeanCreationException if FactoryBean object creation failed
 * @see org.springframework.beans.factory.FactoryBean#getObject()
 */
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // 如果是單例模式
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                object = doGetObjectFromFactoryBean(factory, beanName);
                // Only post-process and store if not put there already during getObject() call above
                // (e.g. because of circular reference processing triggered by custom getBean calls)
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                }
                else {
                    if (shouldPostProcess) {
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            // Temporarily return non-post-processed object, not storing it yet..
                            return object;
                        }
                        beforeSingletonCreation(beanName);
                        try {
                            // 調用ObjectFactory的后處理器
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                        finally {
                            afterSingletonCreation(beanName);
                        }
                    }
                    if (containsSingleton(beanName)) {
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            return object;
        }
    }
    else {
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

很遺憾,在這個代碼中我們還是沒有看到想要看到的代碼,在這個方法里只做了一件事情, 就是返回的bean如果是單例的,那就必須要保證全局唯一,同時,也因為是單例的,所以不必重復創建,可以使用緩存來提高性能,也就是說已經加載過就要記錄下來以便於下次復用, 否則的話就直接獲取了。

在doGetObjectFromFactoryBean方法中我們終於看到了我們想要看到的方法,也就足object = factory.getObjcct(),是的,就是這句代碼,我們的歷程猶如剝洋蔥一樣,一層一層的直到最內部的代碼實現,雖然很簡單。

/**
 * Obtain an object to expose from the given FactoryBean.
 * @param factory the FactoryBean instance
 * @param beanName the name of the bean
 * @return the object obtained from the FactoryBean
 * @throws BeanCreationException if FactoryBean object creation failed
 * @see org.springframework.beans.factory.FactoryBean#getObject()
 */
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
        throws BeanCreationException {

    Object object;
    try {
        // 需要權限驗證
        if (System.getSecurityManager() != null) {
            AccessControlContext acc = getAccessControlContext();
            try {
                object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            // 直接調用getObject方法
            object = factory.getObject();
        }
    }
    catch (FactoryBeanNotInitializedException ex) {
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    }

    // Do not accept a null value for a FactoryBean that's not fully
    // initialized yet: Many FactoryBeans just return null then.
    if (object == null) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        object = new NullBean();
    }
    return object;
}

上面我們已經講述了FactoryBean的調用方法,如果bean聲明為FactoryBean類型,則當提取bean時提取的並不是FactoryBean,而是FactoryBean中對應的getObject方法返冋的bean,而doGetObjectFromFactoryBean正是實現這個功能的。但是,我們看到在上面的方法中除了調用object = factory.getObject()得到我們想要的結果后並沒有直接返回,而是接下來又做了些后處理的操作,這個又是做什么用的呢?於是我們跟蹤進入AbstractAutowireCapableBeanFactory 類的 postProcessObjectFromFactoryBean 方法:

@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
    return applyBeanPostProcessorsAfterInitialization(object, beanName);
}

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

對於后處理器的使用我們還未過多接觸,后續章節會使用大量篇幅介紹,這里,我們只需了解在Spring獲取bean的規則中有這樣一條:盡可能保證所有bean初始化后都會調用注冊的BeanPostProcessor的postProcessAfterlnitialization方法進行處理,在實際開發過程中大可以針對此特性設計自己的業務邏輯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM