Spring IoC源碼分析(注解版) -- 下

前兩篇我們講了BeanDefinition加載以及BeanFactory后置處理器沥阱,主要分析了registry和invokeBeanFactoryPostProcessors這兩個方法蝌衔。今天我們來分析另外兩個重要的方法。registerBeanPostProcessors和finishBeanFactoryInitialization遗锣。這些方法都在AnnotationConfigApplicationContext的refresh方法中生真。

注冊Bean 后置處理器

registerBeanPostProcessors方法負(fù)責(zé)初始化實現(xiàn)了BeanPostProcessor接口的Bean铣除,并將其注冊到BeanFactory中闹丐。

后置處理器BeanPostProcessor定義了兩個方法postProcessBeforeInitialization和postProcessAfterInitialization。Spring會添加所有的BeanPostProcessor到BeanFactory的beanPostProcessors列表中赚导。

BeanPostProcessor可以理解成輔助類茬缩,在所有其它類型的Bean(應(yīng)用Bean)初始化過程中,Spring會分別在它們初始化前后調(diào)用BeanPostProcessor實例的postProcessBeforeInitialization和postProcessAfterInitialization吼旧。

前面講的BeanFactoryPostProcessor凰锡,和BeanPostProcessor是一樣的。在BeanFactory創(chuàng)建之后圈暗,Spring會調(diào)用所有BeanFactoryPostProcessor實例的postProcessBeanFactory方法掂为,這樣為用戶提供了在BeanFactory創(chuàng)建之后,對Bean進(jìn)行擴展的機會员串。

現(xiàn)在來看registerBeanPostProcessors源碼:

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        // 調(diào)用PostProcessorRegistrationDelegate的registerBeanPostProcessors方法
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    }

看PostProcessorRegistrationDelegate的registerBeanPostProcessors的源代碼:

public static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
        // 獲取所有的postProcessor names
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

        
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            // 放到nonOrderedPostProcessorNames列表中勇哗,這里省略了其它代碼,都是處理優(yōu)先級的寸齐。BesnPostProcessor也可以設(shè)置優(yōu)先級的欲诺,優(yōu)先級高的會先被調(diào)用抄谐。                      
            nonOrderedPostProcessorNames.add(ppName);
        }

        

        // Now, register all regular BeanPostProcessors.
        List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
        for (String ppName : nonOrderedPostProcessorNames) {
            // 實例化BeanPostProcessor實例
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            nonOrderedPostProcessors.add(pp);
        }
    
        // 注冊BestProcessor
        registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
    }

看registerBeanPostProcessors源碼:

private static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

        // 把所有的BeanPostProcessor添加到beanFactory中
        for (BeanPostProcessor postProcessor : postProcessors) {
            beanFactory.addBeanPostProcessor(postProcessor);
        }
    }

beanFactory是一個DefaultListableBeanFactory對象,我們來看其代碼扰法,很簡單蛹含,幾乎就是一行代碼:

@Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {     
        // Remove from old position, if any
        this.beanPostProcessors.remove(beanPostProcessor);      
        // 將beanPostProcessor添加到beanPostProcessors列表中
        this.beanPostProcessors.add(beanPostProcessor);
    }

在創(chuàng)建所有的應(yīng)用bean調(diào)用initializeBean方法時,會輪詢beanPostProcessors中的對象塞颁,并在Bean實例化前后分別調(diào)用postProcessBeforeInitialization和postProcessAfterInitialization方法挣惰。

好的,注冊BeanPostProcessor講完了殴边,注冊過程比較簡單锤岸,主要是講了一下它在Spring Bean初始化過程中的作用板乙。我們接下來看最最重要的一個方法finishBeanFactoryInitialization。

初始化Bean對象

refresh方法中我們最后要講的一個方法是finishBeanFactoryInitialization蛋铆,它負(fù)責(zé)根據(jù)BeanDefinition創(chuàng)建Bean對象,并執(zhí)行一些與Bean生命周期相關(guān)的回調(diào)函數(shù)放接。我們直接看源碼:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // 省略其它處理代碼刺啦,直接調(diào)用beanFactory的preInstantiateSingletons.
        beanFactory.preInstantiateSingletons();
    }

始終記住beanFactory是DefaultListableBeanFactory對象,所以看它的preInstantiateSingletons源碼纠脾。

// 這里要注意玛瘸,只初始化所有singletons的Bean,關(guān)于prototype類型的bean,是每次調(diào)用getBean都會創(chuàng)建的苟蹈,不會在容器啟動的時候初始化糊渊。
public void preInstantiateSingletons() throws BeansException {      
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);     
        for (String beanName : beanNames) {
            // 這里省略了FactoryBean對象處理邏輯,如果是isEglarBean慧脱,也會調(diào)用getBean方法渺绒。所以簡單理解為菱鸥,不管是哪種sigleton bean宗兼,都會調(diào)用getBean方法
            getBean(beanName);
        }

        // 省略SmartInitializingSingleton的處理,有興趣的可以去了解一下這個類的作用...     
    }

public Object getBean(String name) throws BeansException {
        // getBean其實調(diào)用了doGetBean方法采缚。
        return doGetBean(name, null, null, false);
    }

來看doGetBean的代碼,為了減少文章內(nèi)容扳抽,只貼了核心代碼:

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

        // 取單利Bean篡帕,這里簡單介紹一下DefaultListableBeanFactory的另一種集成關(guān)系,它繼承了DefaultSingletonBeanRegistry類镰烧。這個類允許單利管理拢军,簡單講就是其中定義了一個HashMap<String,Object>怔鳖,維護(hù)了bean名字和Bean對象的關(guān)系度陆,并且保證每一個Bean名字只創(chuàng)建一個Bean對象。
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            // 如果緩存(上面說的HashMap)中存在bean蹬蚁,則取這個bean
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // BeanFactory是可以繼承的,如果當(dāng)前BeanFactory中找不到Bean定義叽粹,就從父BeanFactory中去找。
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                String nameToLookup = originalBeanName(name);
                // 省略了參數(shù)處理的過程。直接從父BeanFactory去找每强。
                return (T) parentBeanFactory.getBean(nameToLookup);
            }           

            try {
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                // 這里先處理Bean依賴,如果當(dāng)前Bean依賴其它Bean辨绊,則先注冊并實例化依賴的Bean.
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        // 先注冊依賴Bean
                        registerDependentBean(dep, beanName);
                        // 再實例化依賴Bean
                        getBean(dep);
                    }
                }

                // Create bean instance.
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        // 創(chuàng)建單利Bean
                        return createBean(beanName, mbd, args);
                        
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                else if (mbd.isPrototype()) {
                    // Prototyp類型的Bean,是每次都會創(chuàng)建的冻晤。
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                else {
                    // 處理其它類型的Bean,如一些擴展的類型Session鼻弧,Request等等,代碼省略了..
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // 類型轉(zhuǎn)換的代碼也省略了...
        return (T) bean;


來看一下createBean做了哪些事情锦茁。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){  
        // 其它代碼都省略了攘轩,就是調(diào)用了doCreateBean方法
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        return beanInstance;
    }

來看doCreateBean的代碼:

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

        // 創(chuàng)建BeanWrapper.
        BeanWrapper instanceWrapper = null;     
        if (instanceWrapper == null) {
            // 調(diào)用createBeanInstance創(chuàng)建Bean實例,這個方法我們不再仔細(xì)往下閱讀了码俩,大致的思路是根據(jù)RootBeanDefinition找到其類型classType撑刺,然后再獲取其構(gòu)造函數(shù),然后根據(jù)構(gòu)造函數(shù)使用反射動態(tài)創(chuàng)建出一個bean實例握玛,再對這個實例進(jìn)行一下包裝,返回BeanWrapper對象甫菠。當(dāng)需要對bean增強的時候挠铲,創(chuàng)建bean也可能使用CGLib動態(tài)創(chuàng)建,我們這里只講最簡單的情況寂诱。
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();       

        
        Object exposedObject = bean;
        try {
            // 根據(jù)BeanDefinition對bean屬性進(jìn)行賦值拂苹。
            populateBean(beanName, mbd, instanceWrapper);
            // 初始化Bean,在這里執(zhí)行Bean生命周期的回調(diào)函數(shù),如設(shè)置beanName痰洒,調(diào)用postBestProcessor等瓢棒。
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {          
        }

        return exposedObject;
    }

上面的兩個重要方法分別是createBeanInstance和initializeBean。其中createBeanInstance所做的事情大致是根據(jù)RootBeanDefinition找到其類型classType丘喻,然后再獲取其構(gòu)造函數(shù)脯宿,然后根據(jù)構(gòu)造函數(shù)使用反射動態(tài)創(chuàng)建出一個bean實例,再對這個實例進(jìn)行一下包裝泉粉,返回BeanWrapper對象连霉。因為這個類的業(yè)務(wù)很簡單,大部分代碼都是在處理一些與反射有關(guān)的東西嗡靡,所以我們不再進(jìn)行分析了跺撼。我們把重點放在initializeBean這個方法上。

來看initializeBean的代碼:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        // 執(zhí)行*Aware接口的方法讨彼,Spring提供了大量的*Aware接口歉井,用來給Bean設(shè)置值,如可以向Bean中注入ApplicationContext哈误,ClassLoader等哩至。    
        invokeAwareMethods(beanName, bean);

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 如果Bean實現(xiàn)了BeanPostProcessor接口躏嚎,則執(zhí)行postProcessBeforeInitialization方法。
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // 執(zhí)行bean初始化相關(guān)方法憨募。如果bean實現(xiàn)了InitializingBean接口紧索,則會調(diào)用其afterPropertiesSet方法。如果bean指定了用戶自定義的init-method方法菜谣,自定義方法也會被執(zhí)行珠漂。
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // 如果Bean實現(xiàn)了BeanPostProcessor接口,則執(zhí)行postProcessAfterInitialization方法尾膊。
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

上面代碼中相關(guān)接口方法的執(zhí)行都很直接媳危,就是判斷Bean對象是否實現(xiàn)了某個接口,如果實現(xiàn)了該接口冈敛,就調(diào)用接口定義的方法待笑。initializeBean是比較重要的方法,它涉及到了Bean的生命周期抓谴,是面試的衬乎澹考點。它也確實比較重要癌压,我們可以在Bean初始化期間做很多事情仰泻。

到目前為止,Bean初始化也講完了滩届,從finishBeanFactoryInitialization->getBean->createBean->initializeBean集侯。完成了bean的初始化并執(zhí)行Bean生命周期中相關(guān)的回調(diào)方法。

總結(jié)

今天講了注冊bean后置處理器以及bean的加載帜消。

Spring定義了BeanPostProcessor接口棠枉,所有實現(xiàn)了該接口的bean,都將被注冊到spring的后置處理器列表中泡挺。后置處理器相當(dāng)于是一些輔助類辈讶,所有的應(yīng)用bean在初始化之后,都會調(diào)用所有的后置處理器娄猫。這為用戶提供了在bean初始化前后荞估,修改或擴展bean的機會。

然后我們講了最重要的bean加載稚新。ApplicationContext會在啟動容器時勘伺,加載所有的非lazi-init的singleton bean。ApplicationContext實現(xiàn)了BeanDefinitionRegistry接口褂删,并在之前就已經(jīng)注冊了所有的BeanDefination飞醉,將其存儲在一個HashMap中。在加載bean時,從HashMap中讀取所有的BeanDefinition缅帘,并調(diào)用其getBean方法轴术。getBean本意是獲取bean,但是如果沒有钦无,則會創(chuàng)建并進(jìn)行初始化逗栽。

獲取bean時調(diào)用了doGetBean方法,首先會檢查當(dāng)前bean是否有定義失暂,如果沒有定義彼宠,則會去父BeanFactory中去查找。并且它也會檢查當(dāng)前bean是否依賴其它bean弟塞,如果依賴其它bean凭峡,則會先創(chuàng)建所依賴的bean。

創(chuàng)建bean是根據(jù)BeanDefinition中的classType决记,獲取其構(gòu)造函數(shù)摧冀,然后利用反射創(chuàng)建bean實例,然后調(diào)用populateBean方法進(jìn)行屬性設(shè)置系宫,最后調(diào)用initializeBean回調(diào)一些與bean生命周期有關(guān)的接口方法索昂。

至此,整個Spring的容器就啟動了扩借。


所有文章在Github上同步椒惨,你也可以訪問我的個人博客點擊查看

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市往枷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凄杯,老刑警劉巖错洁,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異戒突,居然都是意外死亡屯碴,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門膊存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來导而,“玉大人,你說我怎么就攤上這事隔崎〗褚眨” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵爵卒,是天一觀的道長虚缎。 經(jīng)常有香客問我,道長钓株,這世上最難降的妖魔是什么实牡? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任陌僵,我火速辦了婚禮,結(jié)果婚禮上创坞,老公的妹妹穿的比我還像新娘碗短。我一直安慰自己,他們只是感情好题涨,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布偎谁。 她就那樣靜靜地躺著,像睡著了一般携栋。 火紅的嫁衣襯著肌膚如雪搭盾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天婉支,我揣著相機與錄音鸯隅,去河邊找鬼。 笑死向挖,一個胖子當(dāng)著我的面吹牛蝌以,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播何之,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼跟畅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了溶推?” 一聲冷哼從身側(cè)響起徊件,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒜危,沒想到半個月后虱痕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡辐赞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年部翘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片响委。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡新思,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赘风,到底是詐尸還是另有隱情夹囚,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布邀窃,位于F島的核電站崔兴,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜敲茄,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一位谋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧堰燎,春花似錦掏父、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至仅讽,卻和暖如春陶缺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背洁灵。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工饱岸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人徽千。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓苫费,卻偏偏與公主長得像,于是被迫代替她去往敵國和親双抽。 傳聞我的和親對象是個殘疾皇子百框,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354