2018-05-12

spring源碼分析(四)



目錄

五、spring源碼分析
--5.5、IOC 容器的高級特性
----1、介紹
----2、Spring IOC 容器的 lazy-init 屬性實現(xiàn)預(yù)實例化
------(1).refresh()
------(2).finishBeanFactoryInitialization 處理預(yù)實例化 Bean
------(3).DefaultListableBeanFactory 對配置 lazy-init 屬性單態(tài) Bean 的預(yù)實例化
----3、FactoryBean 的實現(xiàn)
------(1)FactoryBean的源碼
------(2). AbstractBeanFactory 的 getBean 方法調(diào)用 FactoryBean
------(3).AbstractBeanFactory 生產(chǎn) Bean 實例對象
------(4).工廠 Bean 的實現(xiàn)類 getObject 方法創(chuàng)建 Bean 實例對象
----4、BeanPostProcessor 后置處理器的實現(xiàn)
------(1).BeanPostProcessor 的源碼
------(2).AbstractAutowireCapableBeanFactory 類對容器生成的 Bean 添加后置處理器
------(3).initializeBean 方法為容器產(chǎn)生的 Bean 實例對象添加 BeanPostProcessor 后置處理器
------(4).AdvisorAdapterRegistrationManager 在 Bean 對象初始化后注冊通知適配器
----5、Spring IOC 容器 autowiring 實現(xiàn)原理
------(1). AbstractAutoWireCapableBeanFactory 對 Bean 實例進(jìn)行屬性依賴注入
------(2).Spring IOC 容器根據(jù) Bean 名稱或者類型進(jìn)行 autowiring 自動依賴注入
------(3).DefaultSingletonBeanRegistry 的 registerDependentBean 方法對屬性注入



五、spring源碼分析

5.5、IOC 容器的高級特性

1、介紹

通過前面 4 節(jié)對 Spring IOC 容器的源碼分析,我們已經(jīng)基本上了解了 Spring IOC 容器對 Bean 定 義資源的定位、讀入和解析過程,同時也清楚了當(dāng)用戶通過 getBean 方法向 IOC 容器獲取被管理的 Bean 時,IOC 容器對 Bean 進(jìn)行的初始化和依賴注入過程,這些是 Spring IOC 容器的基本功能特性。 Spring IOC 容器還有一些高級特性,如使用 lazy-init 屬性對 Bean 預(yù)初始化、FactoryBean 產(chǎn)生或者 修飾 Bean 對象的生成、 IOC 容器初始化 Bean 過程中使用 BeanPostProcessor 后置處理器對 Bean 聲明周 期事件管理和 IOC 容器的 autowiring 自動裝配功能等。

2、Spring IOC 容器的 lazy-init 屬性實現(xiàn)預(yù)實例化:

通過前面我們對 IOC 容器的實現(xiàn)和工作原理分析,我們知道 IOC 容器的初始化過程就是對 Bean 定義 資源的定位、載入和注冊,此時容器對 Bean 的依賴注入并沒有發(fā)生,依賴注入主要是在應(yīng)用程序第一 次向容器索取 Bean 時,通過 getBean 方法的調(diào)用完成。

當(dāng) Bean 定義資源的<Bean>元素中配置了 lazy-init 屬性時,容器將會在初始化的時候?qū)λ渲玫?Bean 進(jìn)行預(yù)實例化,Bean 的依賴注入在容器初始化的時候就已經(jīng)完成。這樣,當(dāng)應(yīng)用程序第一次向容器索取 被管理的 Bean 時,就不用再初始化和對 Bean 進(jìn)行依賴注入了,直接從容器中獲取已經(jīng)完成依賴注入的 現(xiàn)成 Bean,可以提高應(yīng)用第一次向容器獲取 Bean 的性能。

下面我們通過代碼分析容器預(yù)實例化的實現(xiàn)過程:

(1).refresh()

先從 IOC 容器的初始會過程開始,通過前面文章分析,我們知道 IOC 容器讀入已經(jīng)定位的 Bean 定義資 源是從 refresh 方法開始的,我們首先從 AbstractApplicationContext 類的 refresh 方法入手分析, 源碼如下:

//容器初始化的過程,讀入 Bean 定義資源,并解析注冊
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        //調(diào)用容器準(zhǔn)備刷新的方法,獲取容器的當(dāng)時時間,同時給容器設(shè)置同步標(biāo)識
        prepareRefresh();
        //告訴子類啟動 refreshBeanFactory()方法,Bean 定義資源文件的載入從
        //子類的 refreshBeanFactory()方法啟動
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        //為 BeanFactory 配置容器特性,例如類加載器、事件處理器等
        prepareBeanFactory(beanFactory);
        try {
            //為容器的某些子類指定特殊的 BeanPost 事件處理器
            postProcessBeanFactory(beanFactory);
            //調(diào)用所有注冊的 BeanFactoryPostProcessor 的 Bean
            invokeBeanFactoryPostProcessors(beanFactory);
            //為 BeanFactory 注冊 BeanPost 事件處理器.
            //BeanPostProcessor 是 Bean 后置處理器,用于監(jiān)聽容器觸發(fā)的事件
            registerBeanPostProcessors(beanFactory);
            //初始化信息源,和國際化相關(guān).
            initMessageSource();
            //初始化容器事件傳播器.
            initApplicationEventMulticaster();
            //調(diào)用子類的某些特殊 Bean 初始化方法
            onRefresh();
            //為事件傳播器注冊事件監(jiān)聽器.
            registerListeners();
            //這里是對容器 lazy-init 屬性進(jìn)行處理的入口方法
            finishBeanFactoryInitialization(beanFactory);
            //初始化容器的生命周期事件處理器,并發(fā)布容器的生命周期事件
            finishRefresh();
        }catch (BeansException ex) {
            //銷毀以創(chuàng)建的單態(tài) Bean
            destroyBeans();
            //取消 refresh 操作,重置容器的同步標(biāo)識.
            cancelRefresh(ex);
            throw ex;
        }
    }
}

在 refresh 方法中 ConfigurableListableBeanFactorybeanFactory = obtainFreshBeanFactory(); 啟動了 Bean 定義資源的載入、注冊過程,而 finishBeanFactoryInitialization 方法是對注冊后的 Bean 定義中的預(yù)實例化(lazy-init=false,Spring 默認(rèn)就是預(yù)實例化,即為 true)的 Bean 進(jìn)行處理的地方。

(2).finishBeanFactoryInitialization 處理預(yù)實例化 Bean:

當(dāng)Bean定義資源被載入IOC容器之后,容器將Bean定義資源解析為容器內(nèi)部的數(shù)據(jù)結(jié)構(gòu)BeanDefinition 注冊到容器中, AbstractApplicationContext 類中的 finishBeanFactoryInitialization 方法對配置了 預(yù)實例化屬性的 Bean 進(jìn)行預(yù)初始化過程,源碼如下:

//對配置了 lazy-init 屬性的 Bean 進(jìn)行預(yù)實例化處理
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    //這是 Spring3 以后新加的代碼,為容器指定一個轉(zhuǎn)換服務(wù)(ConversionService)
    //在對某些 Bean 屬性進(jìn)行轉(zhuǎn)換時使用
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
    beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }
    //為了類型匹配,停止使用臨時的類加載器
    beanFactory.setTempClassLoader(null);
    //緩存容器中所有注冊的 BeanDefinition 元數(shù)據(jù),以防被修改
    beanFactory.freezeConfiguration();
    //對配置了 lazy-init 屬性的單態(tài)模式 Bean 進(jìn)行預(yù)實例化處理
    beanFactory.preInstantiateSingletons();
}

ConfigurableListableBeanFactory 是一個接口,其 preInstantiateSingletons 方法由其子類 DefaultListableBeanFactory 提供。

(3).DefaultListableBeanFactory 對配置 lazy-init 屬性單態(tài) Bean 的預(yù)實例化:

public void preInstantiateSingletons() throws BeansException {
    if (this.logger.isInfoEnabled()) {
     this.logger.info("Pre-instantiating singletons in " + this);
    }
    //在對配置 lazy-init 屬性單態(tài) Bean 的預(yù)實例化過程中,必須多線程同步,以確保數(shù)據(jù)一致性
    synchronized (this.beanDefinitionMap) {
        for (String beanName : this.beanDefinitionNames) {
            //獲取指定名稱的 Bean 定義
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            //Bean 不是抽象的,是單態(tài)模式的,且 lazy-init 屬性配置為 false
                if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                    //如果指定名稱的 bean 是創(chuàng)建容器的 Bean
                    if (isFactoryBean(beanName)) {
                    //FACTORY_BEAN_PREFIX=”&”,當(dāng) Bean 名稱前面加”&”符號
                    //時,獲取的是產(chǎn)生容器對象本身,而不是容器產(chǎn)生的 Bean.
                    //調(diào)用 getBean 方法,觸發(fā)容器對 Bean 實例化和依賴注入過程
                    final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX +
                    beanName);
                    //標(biāo)識是否需要預(yù)實例化
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean){
                        //一個匿名內(nèi)部類
                        isEagerInit = AccessController.doPrivileged(new
                            PrivilegedAction<Boolean>() {
                                public Boolean run() {
                                    return ((SmartFactoryBean) factory).isEagerInit();
                                }
                            }, getAccessControlContext());
                    }else {
                        isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)
                        factory).isEagerInit();
                    }
                    if (isEagerInit) {
                        //調(diào)用 getBean 方法,觸發(fā)容器對 Bean 實例化和依賴注入過程
                        getBean(beanName);
                    }
                }else {
                    //調(diào)用 getBean 方法,觸發(fā)容器對 Bean 實例化和依賴注入過程
                    getBean(beanName);
                }
            }
        }
    }
}

通過對 lazy-init 處理源碼的分析,我們可以看出,如果設(shè)置了 lazy-init 屬性,則容器在完成 Bean 定義的注冊之后,會通過 getBean 方法,觸發(fā)對指定 Bean 的初始化和依賴注入過程,這樣當(dāng)應(yīng)用第一 次向容器索取所需的 Bean 時,容器不再需要對 Bean 進(jìn)行初始化和依賴注入,直接從已經(jīng)完成實例化和 依賴注入的 Bean 中取一個現(xiàn)成的 Bean,這樣就提高了第一次獲取 Bean 的性能。

3、FactoryBean 的實現(xiàn):

在 Spring 中,有兩個很容易混淆的類:BeanFactory 和 FactoryBean。

BeanFactory:Bean 工廠,是一個工廠(Factory),我們 Spring IOC 容器的最頂層接口就是這個 BeanFactory,它的作用是管理 Bean,即實例化、定位、配置應(yīng)用程序中的對象及建立這些對象間的依 賴。

FactoryBean:工廠 Bean,是一個 Bean,作用是產(chǎn)生其他 bean 實例。通常情況下,這種 bean 沒有什么 特別的要求,僅需要提供一個工廠方法,該方法用來返回其他 bean 實例。通常情況下,bean 無須自己 實現(xiàn)工廠模式,Spring 容器擔(dān)任工廠角色;但少數(shù)情況下,容器中的 bean 本身就是工廠,其作用是產(chǎn) 生其它 bean 實例。

當(dāng)用戶使用容器本身時,可以使用轉(zhuǎn)義字符”&”來得到 FactoryBean 本身,以區(qū)別通過 FactoryBean 產(chǎn)生的實例對象和 FactoryBean 對象本身。在 BeanFactory 中通過如下代碼定義了該轉(zhuǎn)義字符:

StringFACTORY_BEAN_PREFIX = "&";

如果 myJndiObject 是一個 FactoryBean,則使用&myJndiObject 得到的是 myJndiObject 對象,而不是 myJndiObject 產(chǎn)生出來的對象。

(1).FactoryBean 的源碼:

//工廠 Bean,用于產(chǎn)生其他對象
public interface FactoryBean<T> {
    //獲取容器管理的對象實例
    T getObject() throws Exception;
    //獲取 Bean 工廠創(chuàng)建的對象的類型
    Class<?> getObjectType();
    //Bean 工廠創(chuàng)建的對象是否是單態(tài)模式,如果是單態(tài)模式,則整個容器中只有一個實例
    //對象,每次請求都返回同一個實例對象
    boolean isSingleton();
}

(2). AbstractBeanFactory 的 getBean 方法調(diào)用 FactoryBean:

在前面我們分析 Spring IOC 容器實例化 Bean 并進(jìn)行依賴注入過程的源碼時,提到在 getBean 方法觸 發(fā)容器實例化 Bean 的時候會調(diào)用 AbstractBeanFactory 的 doGetBean 方法來進(jìn)行實例化的過程,源碼 如下:

//真正實現(xiàn)向 IOC 容器獲取 Bean 的功能,也是觸發(fā)依賴注入功能的地方
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean
typeCheckOnly) throws BeansException {
    //根據(jù)指定的名稱獲取被管理 Bean 的名稱,剝離指定名稱中對容器的相關(guān)依賴
    //如果指定的是別名,將別名轉(zhuǎn)換為規(guī)范的 Bean 名稱
    final String beanName = transformedBeanName(name);
    Object bean;
    //先從緩存中取是否已經(jīng)有被創(chuàng)建過的單態(tài)類型的 Bean,對于單態(tài)模式的 Bean 整
    //個 IoC 容器中只創(chuàng)建一次,不需要重復(fù)創(chuàng)建
    Object sharedInstance = getSingleton(beanName);
    //IoC 容器創(chuàng)建單態(tài)模式 Bean 實例對象
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            //如果指定名稱的 Bean 在容器中已有單態(tài)模式的 Bean 被創(chuàng)建,直接返回
            //已經(jīng)創(chuàng)建的 Bean
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName
                +
                "' that is not fully initialized yet - a consequence of a circular
                reference");
            }else {
             logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        //獲取給定 Bean 的實例對象,主要是完成 FactoryBean 的相關(guān)處理
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    ……
}
//獲取給定 Bean 的實例對象,主要是完成 FactoryBean 的相關(guān)處理
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
    //容器已經(jīng)得到了 Bean 實例對象,這個實例對象可能是一個普通的 Bean,
    //也可能是一個工廠 Bean,如果是一個工廠 Bean,則使用它創(chuàng)建一個 Bean 實例對象,
    //如果調(diào)用本身就想獲得一個容器的引用,則指定返回這個工廠 Bean 實例對象
    //如果指定的名稱是容器的解引用(dereference,即是對象本身而非內(nèi)存地址),
    //且 Bean 實例也不是創(chuàng)建 Bean 實例對象的工廠 Bean
    if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
        throw new BeanIsNotAFactoryException(transformedBeanName(name),
            beanInstance.getClass());
    }
    //如果 Bean 實例不是工廠 Bean,或者指定名稱是容器的解引用,
    //調(diào)用者向獲取對容器的引用,則直接返回當(dāng)前的 Bean 實例
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
     return beanInstance;
    }
    //處理指定名稱不是容器的解引用,或者根據(jù)名稱獲取的 Bean 實例對象是一個工廠 Bean
    //使用工廠 Bean 創(chuàng)建一個 Bean 的實例對象
    Object object = null;
    if (mbd == null) {
        //從 Bean 工廠緩存中獲取給定名稱的 Bean 實例對象
        object = getCachedObjectForFactoryBean(beanName);
    }
    //讓 Bean 工廠生產(chǎn)給定名稱的 Bean 對象實例
    if (object == null) {
        FactoryBean factory = (FactoryBean) beanInstance;
        //如果從 Bean 工廠生產(chǎn)的 Bean 是單態(tài)模式的,則緩存
        if (mbd == null && containsBeanDefinition(beanName)) {
            //從容器中獲取指定名稱的 Bean 定義,如果繼承基類,則合并基類相關(guān)屬性
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        //如果從容器得到 Bean 定義信息,并且 Bean 定義信息不是虛構(gòu)的,
        //則讓工廠 Bean 生產(chǎn) Bean 實例對象
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        //調(diào)用 FactoryBeanRegistrySupport 類的 getObjectFromFactoryBean 方法,
        //實現(xiàn)工廠 Bean 生產(chǎn) Bean 對象實例的過程
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

在上面獲取給定 Bean 的實例對象的 getObjectForBeanInstance 方法中,會調(diào)用 FactoryBeanRegistrySupport 類的 getObjectFromFactoryBean 方法,該方法實現(xiàn)了 Bean 工廠生產(chǎn) Bean 實例對象。

Dereference(解引用):一個在 C/C++中應(yīng)用比較多的術(shù)語,在 C++中,”*”是解引用符號,而”&”是 引用符號,解引用是指變量指向的是所引用對象的本身數(shù)據(jù),而不是引用對象的內(nèi)存地址。

(3).AbstractBeanFactory 生產(chǎn) Bean 實例對象:

AbstractBeanFactory 類中生產(chǎn) Bean 實例對象的主要源碼如下

//Bean 工廠生產(chǎn) Bean 實例對象
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean
shouldPostProcess) {
    //Bean 工廠是單態(tài)模式,并且 Bean 工廠緩存中存在指定名稱的 Bean 實例對象
    if (factory.isSingleton() && containsSingleton(beanName)) {
        //多線程同步,以防止數(shù)據(jù)不一致
        synchronized (getSingletonMutex()) {
            //直接從 Bean 工廠緩存中獲取指定名稱的 Bean 實例對象
            Object object = this.factoryBeanObjectCache.get(beanName);
            //Bean 工廠緩存中沒有指定名稱的實例對象,則生產(chǎn)該實例對象
            if (object == null) {
                //調(diào)用 Bean 工廠的 getObject 方法生產(chǎn)指定 Bean 的實例對象
                object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
                //將生產(chǎn)的實例對象添加到 Bean 工廠緩存中
                this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
            }
            return (object != NULL_OBJECT ? object : null);
        }
    }
    //調(diào)用 Bean 工廠的 getObject 方法生產(chǎn)指定 Bean 的實例對象
    else {
        return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
    }
}
//調(diào)用 Bean 工廠的 getObject 方法生產(chǎn)指定 Bean 的實例對象
private Object doGetObjectFromFactoryBean(
final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
throws BeanCreationException {
    Object object;
    try {
        if (System.getSecurityManager() != null) {
            AccessControlContext acc = getAccessControlContext();
            try {
                //實現(xiàn) PrivilegedExceptionAction 接口的匿名內(nèi)置類
                //根據(jù) JVM 檢查權(quán)限,然后決定 BeanFactory 創(chuàng)建實例對象
                object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                        //調(diào)用 BeanFactory 接口實現(xiàn)類的創(chuàng)建對象方法
                        return factory.getObject();
                    }}, acc);
            }catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }else {
            //調(diào)用 BeanFactory 接口實現(xiàn)類的創(chuàng)建對象方法
            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);
    }
    //創(chuàng)建出來的實例對象為 null,或者因為單態(tài)對象正在創(chuàng)建而返回 null
    if (object == null && isSingletonCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(
        beanName, "FactoryBean which is currently in creation returned null from getObject");
    }
    //為創(chuàng)建出來的 Bean 實例對象添加 BeanPostProcessor 后置處理器
    if (object != null && shouldPostProcess) {
        try {
            object = postProcessObjectFromFactoryBean(object, beanName);
        }catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object
            failed", ex);
        }
    }
    return object;
}

從上面的源碼分析中,我們可以看出, BeanFactory 接口調(diào)用其實現(xiàn)類的 getObject 方法來實現(xiàn)創(chuàng)建 Bean 實例對象的功能。

(4).工廠 Bean 的實現(xiàn)類 getObject 方法創(chuàng)建 Bean 實例對象:

FactoryBean的實現(xiàn)類有非常多,比如: Proxy、 RMI、 JNDI、 ServletContextFactoryBean 等等, FactoryBean 接口為 Spring 容器提供了一個很好的封裝機(jī)制,具體的 getObject 有不同的實現(xiàn)類根據(jù)不同的實現(xiàn)策 略來具體提供,我們分析一個最簡單的 AnnotationTestFactoryBean 的實現(xiàn)源碼:

public class AnnotationTestBeanFactory implements FactoryBean<IJmxTestBean> {

    private final FactoryCreatedAnnotationTestBean instance = new
            FactoryCreatedAnnotationTestBean();

    public AnnotationTestBeanFactory() {
        this.instance.setName("FACTORY");
    }
    //AnnotationTestBeanFactory 產(chǎn)生 Bean 實例對象的實現(xiàn)
    public IJmxTestBean getObject() throws Exception {
         return this.instance;
    }
    public Class<? extends IJmxTestBean> getObjectType() {
        return FactoryCreatedAnnotationTestBean.class;
    }
    public boolean isSingleton() {
         return true;
    }
}

其他的 Proxy,RMI,JNDI 等等,都是根據(jù)相應(yīng)的策略提供 getObject 的實現(xiàn)。這里不做一一分析,這 已經(jīng)不是 Spring 的核心功能,有需要的時候再去深入研究。

4、BeanPostProcessor 后置處理器的實現(xiàn):

BeanPostProcessor 后置處理器是 Spring IOC 容器經(jīng)常使用到的一個特性,這個 Bean 后置處理器是一 個監(jiān)聽器,可以監(jiān)聽容器觸發(fā)的 Bean 聲明周期事件。后置處理器向容器注冊以后,容器中管理的 Bean 就具備了接收 IOC 容器事件回調(diào)的能力。

BeanPostProcessor 的使用非常簡單,只需要提供一個實現(xiàn)接口 BeanPostProcessor 的實現(xiàn)類,然后在 Bean 的配置文件中設(shè)置即可。

(1).BeanPostProcessor 的源碼:

package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
public interface BeanPostProcessor {
    //為在 Bean 的初始化前提供回調(diào)入口
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    //為在 Bean 的初始化之后提供回調(diào)入口
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

這兩個回調(diào)的入口都是和容器管理的 Bean 的生命周期事件緊密相關(guān),可以為用戶提供在 Spring IOC 容器初始化 Bean 過程中自定義的處理操作。

(2).AbstractAutowireCapableBeanFactory 類對容器生成的 Bean 添加后置處理器:

BeanPostProcessor后置處理器的調(diào)用發(fā)生在Spring IOC容器完成對Bean實例對象的創(chuàng)建和屬性的依 賴注入完成之后,在對 Spring 依賴注入的源碼分析過程中我們知道,當(dāng)應(yīng)用程序第一次調(diào)用 getBean 方法(lazy-init 預(yù)實例化除外)向 Spring IOC 容器索取指定 Bean 時觸發(fā) Spring IOC 容器創(chuàng)建 Bean 實例對象并進(jìn)行依賴注入的過程,其中真正實現(xiàn)創(chuàng)建 Bean 對象并進(jìn)行依賴注入的方法是 AbstractAutowireCapableBeanFactory 類的 doCreateBean 方法,主要源碼如下

//真正創(chuàng)建 Bean 的方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
    //創(chuàng)建 Bean 實例對象
    ……
    try {
        //對 Bean 屬性進(jìn)行依賴注入
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            //在對 Bean 實例對象生成和依賴注入完成以后,開始對 Bean 實例對象
            //進(jìn)行初始化 ,為 Bean 實例對象應(yīng)用 BeanPostProcessor 后置處理器
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    }catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException)
        ex).getBeanName())) {
            throw (BeanCreationException) ex;
        }
    ……
    //為應(yīng)用返回所需要的實例對象
    return exposedObject;
}

從上面的代碼中我們知道,為 Bean 實例對象添加 BeanPostProcessor 后置處理器的入口的是 initializeBean 方法。

(3).initializeBean 方法為容器產(chǎn)生的 Bean 實例對象添加 BeanPostProcessor 后置處理器:

同樣在 AbstractAutowireCapableBeanFactory 類中, initializeBean 方法實現(xiàn)為容器創(chuàng)建的 Bean 實例 對象添加 BeanPostProcessor 后置處理器,源碼如下:

//初始容器創(chuàng)建的 Bean 實例對象,為其添加 BeanPostProcessor 后置處理器
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd){
    //JDK 的安全機(jī)制驗證權(quán)限
    if (System.getSecurityManager() != null) {
        //實現(xiàn) PrivilegedAction 接口的匿名內(nèi)部類
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            public Object run() {
                invokeAwareMethods(beanName, bean);
                return null;
            }
        }, getAccessControlContext());
    }else {
        //為 Bean 實例對象包裝相關(guān)屬性,如名稱,類加載器,所屬容器等信息
        invokeAwareMethods(beanName, bean);
    }
    Object wrappedBean = bean;
    //對 BeanPostProcessor 后置處理器的 postProcessBeforeInitialization
    //回調(diào)方法的調(diào)用,為 Bean 實例初始化前做一些處理
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    //調(diào)用 Bean 實例對象初始化的方法,這個初始化方法是在 Spring Bean 定義配置
    //文件中通過 init-method 屬性指定的
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }catch (Throwable ex) {
        throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    //對 BeanPostProcessor 后置處理器的 postProcessAfterInitialization
    //回調(diào)方法的調(diào)用,為 Bean 實例初始化之后做一些處理
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}
//調(diào)用 BeanPostProcessor 后置處理器實例對象初始化之前的處理方法
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
    Object result = existingBean;
    //遍歷容器為所創(chuàng)建的 Bean 添加的所有 BeanPostProcessor 后置處理器
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        //調(diào)用 Bean 實例所有的后置處理中的初始化前處理方法,為 Bean 實例對象在
        //初始化之前做一些自定義的處理操作
        result = beanProcessor.postProcessBeforeInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}
//調(diào)用 BeanPostProcessor 后置處理器實例對象初始化之后的處理方法
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
    Object result = existingBean;
    //遍歷容器為所創(chuàng)建的 Bean 添加的所有 BeanPostProcessor 后置處理器
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        //調(diào)用 Bean 實例所有的后置處理中的初始化后處理方法,為 Bean 實例對象在
        //初始化之后做一些自定義的處理操作
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}

BeanPostProcessor 是一個接口,其初始化前的操作方法和初始化后的操作方法均委托其實現(xiàn)子類來實 現(xiàn),在 Spring 中,BeanPostProcessor 的實現(xiàn)子類非常的多,分別完成不同的操作,如:AOP 面向切面編程的注冊通知適配器、Bean 對象的數(shù)據(jù)校驗、Bean 繼承屬性/方法的合并等等,我們以最簡單的 AOP 切面織入來簡單了解其主要的功能。

(4).AdvisorAdapterRegistrationManager 在 Bean 對象初始化后注冊通知適配器:

AdvisorAdapterRegistrationManager 是 BeanPostProcessor 的一個實現(xiàn)類,其主要的作用為容器中管 理的 Bean 注冊一個面向切面編程的通知適配器,以便在 Spring 容器為所管理的 Bean 進(jìn)行面向切面編 程時提供方便,其源碼如下:

//為容器中管理的 Bean 注冊一個面向切面編程的通知適配器
public class AdvisorAdapterRegistrationManager implements BeanPostProcessor {
    //容器中負(fù)責(zé)管理切面通知適配器注冊的對象
    private AdvisorAdapterRegistry advisorAdapterRegistry =
        GlobalAdvisorAdapterRegistry.getInstance();
    
    public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
         this.advisorAdapterRegistry = advisorAdapterRegistry;
    }
    //BeanPostProcessor 在 Bean 對象初始化前的操作
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
    {
        //沒有做任何操作,直接返回容器創(chuàng)建的 Bean 對象
        return bean;
    }
    //BeanPostProcessor 在 Bean 對象初始化后的操作
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
    {
        if (bean instanceof AdvisorAdapter){
            //如果容器創(chuàng)建的 Bean 實例對象是一個切面通知適配器,則向容器的注冊
            this.advisorAdapterRegistry.registerAdvisorAdapter((AdvisorAdapter) bean);
        }
        return bean;
    }
}

其他的 BeanPostProcessor 接口實現(xiàn)類的也類似,都是對 Bean 對象使用到的一些特性進(jìn)行處理,或者 向 IOC 容器中注冊,為創(chuàng)建的 Bean 實例對象做一些自定義的功能增加,這些操作是容器初始化 Bean 時 自動觸發(fā)的,不需要認(rèn)為的干預(yù)。

5、Spring IOC 容器 autowiring 實現(xiàn)原理:

Spring IOC 容器提供了兩種管理 Bean 依賴關(guān)系的方式:

a.顯式管理:通過 BeanDefinition 的屬性值和構(gòu)造方法實現(xiàn) Bean 依賴關(guān)系管理。

b.autowiring:Spring IOC 容器的依賴自動裝配功能,不需要對 Bean 屬性的依賴關(guān)系做顯式的聲明, 只需要在配置好 autowiring 屬性,IOC 容器會自動使用反射查找屬性的類型和名稱,然后基于屬性的類 型或者名稱來自動匹配容器中管理的 Bean,從而自動地完成依賴注入。

通過對 autowiring 自動裝配特性的理解,我們知道容器對 Bean 的自動裝配發(fā)生在容器對 Bean 依賴注 入的過程中。在前面對 Spring IOC 容器的依賴注入過程源碼分析中,我們已經(jīng)知道了容器對 Bean 實 例對象的屬性注入的處理發(fā)生在 AbstractAutoWireCapableBeanFactory 類中的 populateBean 方法中, 我們通過程序流程分析 autowiring 的實現(xiàn)原理:

(1). AbstractAutoWireCapableBeanFactory 對 Bean 實例進(jìn)行屬性依賴注入:

應(yīng)用第一次通過 getBean 方法(配置了 lazy-init 預(yù)實例化屬性的除外)向 IoC 容器索取 Bean 時,容器 創(chuàng)建 Bean 實例對象,并且對 Bean 實例對象進(jìn)行屬性依賴注入,AbstractAutoWireCapableBeanFactory 的 populateBean 方法就是實現(xiàn) Bean 屬性依賴注入的功能,其主要源碼如下:

protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {
    //獲取 Bean 定義的屬性值,并對屬性值進(jìn)行處理
    PropertyValues pvs = mbd.getPropertyValues();
    ……
    //對依賴注入處理,首先處理 autowiring 自動裝配的依賴注入
    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
     mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        //根據(jù) Bean 名稱進(jìn)行 autowiring 自動裝配處理
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        //根據(jù) Bean 類型進(jìn)行 autowiring 自動裝配處理
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
    }
    //對非 autowiring 的屬性進(jìn)行依賴注入處理
    ……
}

(2).Spring IOC 容器根據(jù) Bean 名稱或者類型進(jìn)行 autowiring 自動依賴注入:

//根據(jù)名稱對屬性進(jìn)行自動依賴注入
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs){
    //對 Bean 對象中非簡單屬性(不是簡單繼承的對象,如 8 中原始類型,字符串,URL 等都是簡單屬性)進(jìn)行處理
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        //如果 Spring IOC 容器中包含指定名稱的 Bean
        if (containsBean(propertyName)) {
            //調(diào)用 getBean 方法向 IoC 容器索取指定名稱的 Bean 實例,迭代觸發(fā)屬性的初始化和依賴注入
            Object bean = getBean(propertyName);
            //為指定名稱的屬性賦予屬性值
            pvs.add(propertyName, bean);
            //指定名稱屬性注冊依賴 Bean 名稱,進(jìn)行屬性依賴注入
            registerDependentBean(propertyName, beanName);
            if (logger.isDebugEnabled()) {
                logger.debug("Added autowiring by name from bean name '" + beanName +
                "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
            }
        }else {
            if (logger.isTraceEnabled()) {
                logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + "' by name: no matching bean found");
            }
        }
    }
}
//根據(jù)類型對屬性進(jìn)行自動依賴注入
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs)
{
    //獲取用戶定義的類型轉(zhuǎn)換器
    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
         converter = bw;
    }
    //存放解析的要注入的屬性
    Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);
    //對 Bean 對象中非簡單屬性(不是簡單繼承的對象,如 8 中原始類型,字符
    //URL 等都是簡單屬性)進(jìn)行處理
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        try {
            //獲取指定屬性名稱的屬性描述器
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            //不對 Object 類型的屬性進(jìn)行 autowiring 自動依賴注入
            if (!Object.class.equals(pd.getPropertyType())) {
                //獲取屬性的 setter 方法
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                //檢查指定類型是否可以被轉(zhuǎn)換為目標(biāo)對象的類型
                boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());
                //創(chuàng)建一個要被注入的依賴描述
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam,
                eager);
                //根據(jù)容器的 Bean 定義解析依賴關(guān)系,返回所有要被注入的 Bean 對象
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames,
                converter);
                if (autowiredArgument != null) {
                    //為屬性賦值所引用的對象
                    pvs.add(propertyName, autowiredArgument);
                }
                for (String autowiredBeanName : autowiredBeanNames) {
                //指定名稱屬性注冊依賴 Bean 名稱,進(jìn)行屬性依賴注入
                    registerDependentBean(autowiredBeanName, beanName);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Autowiring by type from bean name '" + beanName + "' via
                        property '" +
                        propertyName + "' to bean named '" + autowiredBeanName + "'");
                    }
                }
                //釋放已自動注入的屬性
                autowiredBeanNames.clear();
            }
        }catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName,
             propertyName, ex);
        }
    }
}

通過上面的源碼分析,我們可以看出來通過屬性名進(jìn)行自動依賴注入的相對比通過屬性類型進(jìn)行自動依 賴注入要稍微簡單一些,但是真正實現(xiàn)屬性注入的是 DefaultSingletonBeanRegistry 類的 registerDependentBean 方法。

(3).DefaultSingletonBeanRegistry 的 registerDependentBean 方法對屬性注入:

//為指定的 Bean 注入依賴的 Bean
public void registerDependentBean(String beanName, String dependentBeanName) {
    //處理 Bean 名稱,將別名轉(zhuǎn)換為規(guī)范的 Bean 名稱
    String canonicalName = canonicalName(beanName);
    //多線程同步,保證容器內(nèi)數(shù)據(jù)的一致性
    //先從容器中:bean 名稱-->全部依賴 Bean 名稱集合找查找給定名稱 Bean 的依賴 Bean
    synchronized (this.dependentBeanMap) {
        //獲取給定名稱 Bean 的所有依賴 Bean 名稱
        Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
        if (dependentBeans == null) {
            //為 Bean 設(shè)置依賴 Bean 信息
            dependentBeans = new LinkedHashSet<String>(8);
            this.dependentBeanMap.put(canonicalName, dependentBeans);
        }
        //向容器中:bean 名稱-->全部依賴 Bean 名稱集合添加 Bean 的依賴信息
        //即,將 Bean 所依賴的 Bean 添加到容器的集合中
        dependentBeans.add(dependentBeanName);
    }
    //從容器中:bean 名稱-->指定名稱 Bean 的依賴 Bean 集合找查找給定名稱 Bean 的依賴 Bean
    synchronized (this.dependenciesForBeanMap) {
        Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
        if (dependenciesForBean == null) {
            dependenciesForBean = new LinkedHashSet<String>(8);
            this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
        }
        //向容器中:bean 名稱-->指定 Bean 的依賴 Bean 名稱集合添加 Bean 的依賴信息
        //即,將 Bean 所依賴的 Bean 添加到容器的集合中
        dependenciesForBean.add(canonicalName);
    }
}

通過對 autowiring 的源碼分析,我們可以看出,autowiring 的實現(xiàn)過程:

a.對 Bean 的屬性代調(diào)用 getBean 方法,完成依賴 Bean 的初始化和依賴注入。

b.將依賴 Bean 的屬性引用設(shè)置到被依賴的 Bean 屬性上。

c.將依賴 Bean 的名稱和被依賴 Bean 的名稱存儲在 IOC 容器的集合中。

Spring IOC 容器的 autowiring 屬性自動依賴注入是一個很方便的特性,可以簡化開發(fā)時的配置,但是凡是都有兩面性, 自動屬性依賴注入也有不足,首先,Bean 的依賴關(guān)系在配置文件中無法很清楚地看出來,對于維護(hù)造成一定困難。其 次,由于自動依賴注入是 Spring 容器自動執(zhí)行的,容器是不會智能判斷的,如果配置不當(dāng),將會帶來無法預(yù)料的后果, 所以自動依賴注入特性在使用時還是綜合考慮。

最后編輯于
?著作權(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ù)。

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

  • 文章作者:Tyan博客:noahsnail.com | CSDN | 簡書 3.8 Container Exten...
    SnailTyan閱讀 1,305評論 0 6
  • 注意LifecycleProcessor接口繼承了Lifcycle接口。同時,增加了2個方法,用于處理容器的ref...
    google666s閱讀 1,184評論 0 51
  • 什么是Spring Spring是一個開源的Java EE開發(fā)框架。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,771評論 1 133
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,537評論 19 139
  • 這是關(guān)于藏客小伙伴的第一個故事 我叫陳咪咪,陳外是我的藝名,西藏這個地方嘛!沒來的時候想的抓心撓肺,來了之后,發(fā)現(xiàn)...
    藏客旅行閱讀 634評論 0 9

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