spring源碼閱讀2-1——bean的管理

本文開始久脯,將利用《spring源碼閱讀1——環(huán)境搭建&閱讀方法》中提到的方法逐步對(duì)spring源碼進(jìn)行解讀霞怀。

本文主要對(duì)DefaultListtableBeanFactory的父級(jí)接口進(jìn)行剖析、解讀距帅,旨在探究明白spring是如何
對(duì)組件(bean)進(jìn)行管理的抖仅。
本文使用的spring版本:4.1.1.RELEASE

順藤摸瓜——DefaultListableBeanFactory

public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        HelloService helloService = context.getBean(HelloService.class);
        System.out.println(helloService.sayHello());
    }

還是從這個(gè)main函數(shù)入手,容器的getBean(Class<T> requiredType)方法咏窿,是通過類對(duì)象來獲取實(shí)例對(duì)象斟或,通過調(diào)試可以知道,該方法的具體實(shí)現(xiàn)在

AbstractApplicationContext.java

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        assertBeanFactoryActive();
        return getBeanFactory().getBean(requiredType);
    }

查看getBeanFactory()方法

AbstractRefreshableApplicationContext.java

    /** Bean factory for this context */
    private DefaultListableBeanFactory beanFactory;

        ...

    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() {
        synchronized (this.beanFactoryMonitor) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("BeanFactory not initialized or already closed - " +
                        "call 'refresh' before accessing beans via the ApplicationContext");
            }
            return this.beanFactory;
        }
    }

通過debug過程中集嵌,可以看到這個(gè)beanFactory的類型是DefaultListableBeanFactory萝挤。

beanFactory

繼續(xù)調(diào)試,進(jìn)入getBean方法根欧,可以看到這個(gè)方法的具體實(shí)現(xiàn)確實(shí)在類DefaultListableBeanFactory中

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBean(requiredType, (Object[]) null);
    }

    @Override
    public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
        Assert.notNull(requiredType, "Required type must not be null");
        String[] beanNames = getBeanNamesForType(requiredType);
        if (beanNames.length > 1) {
            ArrayList<String> autowireCandidates = new ArrayList<String>();
            for (String beanName : beanNames) {
                if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
                    autowireCandidates.add(beanName);
                }
            }
            if (autowireCandidates.size() > 0) {
                beanNames = autowireCandidates.toArray(new String[autowireCandidates.size()]);
            }
        }
        ...
    }

至此怜珍,我感覺已經(jīng)找到了所謂的“瓜”,就是DefaultListableBeanFactory這個(gè)類凤粗,暫且不糾結(jié)這個(gè)beanFactory是如何實(shí)例化的酥泛,這不是本文的重點(diǎn)。


化整為零

這一節(jié)嫌拣,我們將整理出DefaultListableBeanFactory這個(gè)類的層次結(jié)構(gòu)柔袁,逐步了解各個(gè)關(guān)聯(lián)的類的作用。

子類

通過工具异逐,查看DefaultListableBeanFactory有哪些子類

DefaultListableBeanFactory的子類

可以看到DefaultListableBeanFactory只有一個(gè)子類XmlBeanFactory捶索。回顧spring中bean的幾種裝配方式灰瞻,在對(duì)照該類的注釋腥例,可知這個(gè)類就是使用xml文件來裝配bean組件的。后面的章節(jié)會(huì)詳細(xì)介紹這個(gè)類酝润,這里不做贅述院崇。

父級(jí)層次結(jié)構(gòu)

同樣的,用工具查看DefaultListableBeanFactory的層級(jí)結(jié)構(gòu)以及類圖

小技巧:
Ctrl + H 展示當(dāng)前類的層級(jí)結(jié)構(gòu)圖:左上角可選父類袍祖、子類以及全部展示視圖
Ctrl + Alt + Shift + U 展示當(dāng)前類的類圖底瓣,可過濾展示內(nèi)容
DefaultListableBeanFactory的父類
類圖

通過這個(gè)圖可以知道DefaultListableBeanFactory繼承了AbstractAutowireCapableBeanFactory類,并且實(shí)現(xiàn)了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口蕉陋,已經(jīng)可以清晰地從全局角度了解DefaultListableBeanFactory的脈絡(luò)捐凭。


各個(gè)擊破——接口

小技巧:
Ctrl + F12 查看當(dāng)前類的所有方法和屬性
AliasRegistry
alias注冊(cè)管理

在對(duì)bean進(jìn)行定義時(shí),除了使用id屬性來指定名稱之外凳鬓,為了提供多個(gè)名稱茁肠,可以使用alias標(biāo)簽來指定。該接口定義了對(duì)alias的注冊(cè)管理功能缩举。

getAliases()  :  獲取alias標(biāo)簽數(shù)組
isAlias()  :  判斷標(biāo)簽是否存在
registerAlias()  :  注冊(cè)alias標(biāo)簽
removeAlias()  :  移除已注冊(cè)的alias標(biāo)簽
BeanDefinitionRegistry
bean配置清單管理

提供bean的配置清單注冊(cè)管理功能垦梆。

方法說明:
registerBeanDefinition()  :  注冊(cè)BeanDefinition
removeBeanDefinition()  :  移除BeanDefinition
isBeanNameInUse()  :  重名校驗(yàn)
containsBeanDefinition()  :  工廠中是否存在BeanDefinition
getBeanDefinitionCount()  :  返回工廠中BeanDefinition的總數(shù)
getBeanDefinitionNames()  :  返回工廠中BeanDefinition的名稱


bean的配置清單(BeanDefinition)是什么匹颤?
回憶下spring中,根據(jù)xml文檔來裝配bean托猩,舉個(gè)栗子:
<bean id="123" class="com.spring.student">   
    <property name="name" value="XiaoMing" />   
    <property name="age" value="17" />
    <property name="sex" value="man" />
</bean>  
這是一個(gè)student實(shí)例的配置文件印蓖,里面記錄著id為123的student實(shí)例的姓名、年齡和
性別三個(gè)屬性京腥,spring讀取以后就保存為BeanDefinition赦肃,容器可以根據(jù)這個(gè)信息進(jìn)行
實(shí)例化。這就是配置清單~
BeanFactory

查看BeanFactory接口中定義的方法:

基本的bean管理工廠

BeanFactory接口公浪,定義了一個(gè)基本的bean管理工廠他宛。

方法說明:
containsBean()  :  工廠中是否存在bean實(shí)例
getAliases()  :  獲取實(shí)例bean的別名數(shù)組
getBean()  :  獲取bean實(shí)例(多個(gè)重載方法)
getType()  ;  獲取bean實(shí)例類型
isPrototype()  :  bean實(shí)例是否為prototype
isSingleton()  :  bean實(shí)例是否為單例
isTypeMatch()  :  bean實(shí)例類型是否和給定值匹配
ListableBeanFactory
bean配置清單的管理

這個(gè)接口是對(duì)BeanFactory的擴(kuò)展,提供了根據(jù)條件獲取bean的配置清單(BeanDefinition欠气,暫且就這么稱呼吧)厅各。

方法說明:
containsBeanDefinition()  :  工廠中是否存在BeanDefinition
getBeanDefinitionCount()  :  返回工廠中BeanDefinition的總數(shù)
getBeanDefinitionNames()  :  返回工廠中BeanDefinition的名稱
getBeanNamesForType()  :  根據(jù)類型獲取BeanDefinition的名稱
getBeansOfType()  :  根據(jù)類型獲取Bean
getBeanNamesForAnnotation()  :  根據(jù)注解獲取Bean名稱
getBeansWithAnnotation()  :  根據(jù)注解獲取Bean
findAnnotationOnBean()  :  獲取BeanDefinition的注解

HierarchicalBeanFactory
分層的BeanFactory

同樣是繼承于BeanFactory,這個(gè)接口主要和層級(jí)關(guān)系相關(guān)预柒,包含兩個(gè)方法:

方法說明:
getParentBeanFactory()  :  獲取父級(jí)BeanFactory
containsLocalBean()  :  返回當(dāng)前BeanFactory是否存在bean

如果對(duì)方法的作用有所疑問队塘,也沒有關(guān)系,到后面碰到對(duì)其實(shí)現(xiàn)和使用卫旱,便會(huì)豁然開朗。
AutowireCapableBeanFactory
依賴注入BeanFactory

這個(gè)接口為BeanFactory定義了支持依賴注入功能围段,主要包含:

方法說明:
createBean()  :  創(chuàng)建bean實(shí)例
autowireBean()  :  注入bean實(shí)例
configureBean()  :  配置bean實(shí)例顾翼,注入bean屬性,執(zhí)行回調(diào)函數(shù)等
resolveDependency()  :  解決bean實(shí)例的依賴
autowireBeanProperties()  :  注入bean實(shí)例的屬性
applyBeanPropertyValues()  :  注入bean實(shí)例的屬性值
initializeBean()  :  初始化bean實(shí)例
applyBeanPostProcessorsBeforeInitialization()  :  應(yīng)用bean的前置處理
applyBeanPostProcessorsAfterInitialization()  :  應(yīng)用bean的后置處理
destroyBean()  :  銷毀bean實(shí)例
SigletonBeanRegistry
單例SingletonBean注冊(cè)管理

這個(gè)接口定義了容器對(duì)單例的注冊(cè)管理方法奈泪。

方法說明:
registerSingleton()  :  注冊(cè)bean
getSingleton()  :  獲取bean
containsSingleton()  :  返回是否包含bean
getSingletonNames()  :  獲取bean實(shí)例(單例)的名稱數(shù)組
getSingletonCount()  :  獲取容器中bean實(shí)例的總數(shù)
ConfigurableBeanFactory
bean工廠的配置

這個(gè)接口繼承了SingletonBeanRegistry和HierarchicalBeanFactory兩個(gè)接口适贸,增加了beanFactory的配置功能。主要是許多屬性的get和set方法涝桅。由于配置項(xiàng)較多拜姿,較為復(fù)雜,這里先不詳細(xì)介紹

ConfigurableListableBeanFactory
bean工廠的配置

新增了忽略類型以及接口

總結(jié)

至此冯遂,已經(jīng)了解完所有的相關(guān)接口蕊肥,整理下所有的接口中定義的概念:

  • Bean : 組件對(duì)象,sping容器所管理的對(duì)象
  • SingletonBean : 特殊的bean蛤肌,其在容器中僅有一個(gè)實(shí)例
  • BeanDefinition : bean的配置清單壁却,或者說定義文件,spring可以根據(jù)該文件實(shí)例化出對(duì)象
  • Alias : bean的別名裸准,一個(gè)bean可以有多個(gè)名稱
  • BeanFactory : bean工廠展东,為其他組件提供管理容器
BeanFactory的整體框架

通過這個(gè)類圖,感覺整個(gè)BeanFactory生態(tài)圈已經(jīng)構(gòu)建起來了炒俱。不得不感嘆面向?qū)ο蟮镊攘ρ嗡啵瑑H僅是定義了接口爪膊,便展示了一個(gè)完整的功能模塊。

本文到這就要結(jié)束了砸王,回顧下
    1推盛、首先是通過調(diào)試的方法,找到了整個(gè)bean管理功能模塊的核心DefaultListableBeanFactory
    2处硬、然后是對(duì)DefaultListableBeanFactory所實(shí)現(xiàn)的各個(gè)父級(jí)接口進(jìn)行源碼閱讀和分析
    3小槐、最后再通過系統(tǒng)的整理出該功能模塊的概覽
    通過以上三步,完成了BeanFactory的整個(gè)功能定義的概覽荷辕,下次會(huì)給大家?guī)淼氖侨绾我徊揭徊降?實(shí)現(xiàn)上述的定義

本文到此就結(jié)束凿跳,希望能夠幫到大家。
純屬原創(chuàng)疮方,轉(zhuǎn)載請(qǐng)聲明出處控嗜。
                                                    ——作者:陳來件(QQ:810522442)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市骡显,隨后出現(xiàn)的幾起案子疆栏,更是在濱河造成了極大的恐慌,老刑警劉巖惫谤,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壁顶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡溜歪,警方通過查閱死者的電腦和手機(jī)若专,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝴猪,“玉大人调衰,你說我怎么就攤上這事∽在澹” “怎么了嚎莉?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)沛豌。 經(jīng)常有香客問我趋箩,道長(zhǎng),這世上最難降的妖魔是什么加派? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任阁簸,我火速辦了婚禮,結(jié)果婚禮上哼丈,老公的妹妹穿的比我還像新娘启妹。我一直安慰自己,他們只是感情好醉旦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布饶米。 她就那樣靜靜地躺著桨啃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪檬输。 梳的紋絲不亂的頭發(fā)上照瘾,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音丧慈,去河邊找鬼析命。 笑死,一個(gè)胖子當(dāng)著我的面吹牛逃默,可吹牛的內(nèi)容都是我干的鹃愤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼完域,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼软吐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吟税,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤凹耙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后肠仪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肖抱,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年异旧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了意述。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡泽艘,死狀恐怖欲险,靈堂內(nèi)的尸體忽然破棺而出镐依,到底是詐尸還是另有隱情匹涮,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布槐壳,位于F島的核電站然低,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏务唐。R本人自食惡果不足惜雳攘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枫笛。 院中可真熱鬧吨灭,春花似錦、人聲如沸刑巧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吠冤,卻和暖如春浑彰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拯辙。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工郭变, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涯保。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓诉濒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親遭赂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子循诉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容