Spring源碼--BeanFactory

BeanFactory

Spring Ioc 是一個(gè)管理Bean的容器,在Spring的定義中,他要求所有的Ioc容器都需要實(shí)現(xiàn)接口BeanFactory字支。==BeanFactory是一個(gè)頂級容器接口。==

public interface BeanFactory {

    // 前綴
    String FACTORY_BEAN_PREFIX = "&";

    // 根據(jù)名稱獲取bean
    Object getBean(String name) throws BeansException;

    // 根據(jù)名稱獲取bean,返回指定類型
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    // 根據(jù)名稱獲取bean梨撞,使用指定的參數(shù)初始化
    Object getBean(String name, Object... args) throws BeansException;

    // 根據(jù)類型獲取bean
    <T> T getBean(Class<T> requiredType) throws BeansException;

    // 根據(jù)類型獲取bean,使用指定的參數(shù)初始化
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    // 根據(jù)類型獲取bean提供者
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    // 是否存在指定名稱的bean
    boolean containsBean(String name);

    // 指定的bean是否是單例
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    // 指定的bean是否是原型
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    // 是否類型匹配
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    // 獲取指定bean的類型
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

    // 獲取bean的別名
    String[] getAliases(String name);

}

BeanFactory中含有多個(gè)getBean方法香罐,這是Ioc容器最重要的方法之一卧波,主要是從Ioc容器中獲取Bean。這些getBean的方法中有按類型庇茫、按名稱獲取bean港粱,這也是說,在Spring Ioc容器中旦签,允許按照名稱或者類型獲取bean.

由于BeanFacttory的功能還不夠強(qiáng)大查坪,因此Spring在BeanFactory的基礎(chǔ)上,還設(shè)計(jì)了更為高級的接口:ApplicationContext宁炫,這是BeanFactory的子接口之一,在Spring的體系中BeanFactoryApplicationContext是最為重要的接口設(shè)計(jì)偿曙,實(shí)際使用的大部分Spring Ioc容器是ApplicationContext接口的實(shí)現(xiàn)類。

ApplicationContext

ApplicationContext接口通過集成上級接口羔巢,進(jìn)而集成BeanFactory接口望忆。在BeanFactory的基礎(chǔ)上,擴(kuò)展了消息國際化接口(MessageSource)和資源模式解析接口(ResourcePatternResolver)竿秆。

容器的基本使用

我們在idea中創(chuàng)建一個(gè)springboot的工程启摄,只需要lombok和web的starter即可。(gradle)

image-20200820193932622

我們這里創(chuàng)建了spring boot的工程幽钢,但是只是使用gradle自動(dòng)下載spring的依賴即可歉备。

還記得一個(gè)spring項(xiàng)目是如何創(chuàng)建的嗎?

復(fù)習(xí)一下:

spring--hello~!(如何搭建一個(gè)spring項(xiàng)目)

spring核心容器創(chuàng)建的兩種方式

省去依賴包搅吁,我們創(chuàng)建一個(gè)spring的項(xiàng)目

image-20200820194405030

新增bean

image-20200820194429874

新增beans.xml

image-20200820194453702

然后注釋掉spring boot中原來的代碼威创,添加我們的代碼

image-20200820194528160

運(yùn)行

dGzMut.gif

可以看到落午,最終,我們打印出了people的name.也就是說肚豺,通過XmlBeanFactory加載了我們制定的配置文件后溃斋,使用指定的配置文件,創(chuàng)建了我們需要的Ioc容器吸申。最后我們可以通過名字獲取bean梗劫。

XmlBeanFactory源碼

雖然XmlBeanFactory基本上沒有人在使用,而且也被標(biāo)記為廢棄了截碴,但是梳侨,作為我spring入門的一個(gè)方法,我還是想看看其具體的實(shí)現(xiàn)日丹。

這是XmlBeanFactory的UML圖:

image

我們可以看到走哺,XmlBeanFactory直接繼承DefaultListableBeanFactory,而DefaultListableBeanFactory上面又有非常多的繼承關(guān)系。

  • AliasRegistry:定義對alias的簡單增刪改等操作哲虾。
  • SimpleAliasRegistry:主要使用Map作為alias的緩存丙躏,并對接口AliasRegistry進(jìn)行實(shí)現(xiàn)。
  • SingletonBeanRegistry:定義對單例的注冊及獲取束凑。
  • BeanFactry:定義獲取bean及bean的各種特性晒旅。
  • DefaultSingletonBeanRegistry:對接口SingletonBeanRegistry的實(shí)現(xiàn)。
  • HierarchicalBeanFactory:繼承BeanFactory汪诉,也就是在BeanFactory定義的功能的基礎(chǔ)上增加了對parentFactory的支持废恋。
  • BeanDefinitionRegistry:定義對BeanDefinition的各種增刪改操作。
  • FactoryBeanRegistrySupport:在DefaultSingletonBeanRegistry基礎(chǔ)上增加了對BeanFactory的特殊處理扒寄。
  • ConfigurableBeanFactory:提供配置Factory的各種方法鱼鼓。
  • ListableBeanFactory:根據(jù)各種條件獲取bean的配置清單。
  • AbstractBeanFactory:綜合FactoryBeanRegistrySupportConfigurableBeanFactory的功能该编。
  • AutowireCapableBeanFactory:提供創(chuàng)建bean蚓哩、自動(dòng)注入、初始化以及應(yīng)用bean的后處理器上渴。
  • AbstractAutowireCapableBeanFactoryA:綜合AbstractBeanFactory并對接口AutowireCapableBeanFactory進(jìn)行實(shí)現(xiàn)。
  • ConfigurableListableBeanFactory:BeanFactory配置清單喜颁,指定忽略類型及接口等稠氮。
  • DefaultListableBeanFactory:綜合上述全部功能,主要是對Bean進(jìn)行注冊后的處理半开。

XmlBeanFactoryDefaultListableBeanFactory進(jìn)行了擴(kuò)展隔披,從Xml文檔中讀取BeanDefinition,對于注冊和獲取都是使用的父類繼承的方法寂拆。

image-20200820202243293

XmlBeanDefinitionReader

這是XmlBeanDefinitionReader的UML圖

image

這些類主要的操作:

  • ResourceLoader:定義資源加載器奢米,主要應(yīng)用于根據(jù)給定的資源文件地址返回對應(yīng)的Resource抓韩。
  • BeanDefinitionReader:主要定義自語言文件讀取并轉(zhuǎn)換為BeanDefinition的各個(gè)功能。
  • EnvironmentCapable:定義獲取Environment方法鬓长。
  • DockumentLoader:定義從資源文件加載到轉(zhuǎn)換為Document的功能谒拴。
  • AbstractBeanDefinitionReader:對EnvironmentCapable,BeanDefinitionReader類定義的功能進(jìn)行實(shí)現(xiàn)。
  • BeanDefinitionDocumentReader定義讀取Document并注冊BeanDefinition功能涉波。
  • BeanDefinitionParserDelegate:定義解析Element的各種方法英上。

XmlBeanFactory

我們看下XmlBeanFactory的時(shí)序圖:

image

在main方法中首先調(diào)用ClassPathResource的構(gòu)造方法來構(gòu)造Resource資源文件的實(shí)例對象,這樣后續(xù)的資源處理就可以用Resource提供的服務(wù)進(jìn)行操作啤覆,有了Resource后苍日,就可以進(jìn)行XmlBeanFactory的初始化了。

配置文件的封裝

Spring的配置文件讀取是通過ClassPathResource進(jìn)行封裝的窗声,比如new ClassPathResource("beans.xml")相恃。

在java中,將不同來源的資源抽象成URL笨觅,通過注冊不同的handler(URLStreamHandler)來處理不同來源的資源的讀取邏輯拦耐,一般handler的類型使用不同的前綴來識別,比如:file:,http:,jar:等屋摇。但是URL沒有默認(rèn)定義相對ClassPath或者ServletContext等資源的handler揩魂,雖然可以注冊自己的URLStreamHandler來解析特定的URL前綴(比如cclasspath:),這樣需要了解URL的實(shí)現(xiàn)機(jī)制,而且URL也沒有提供基本方法檢查資源是否存在等炮温。所以Spring對內(nèi)部使用到的資源資源實(shí)現(xiàn)了自己的抽象結(jié)構(gòu):Resource

這是Resource的方法

image-20200822144138299

Resource接口抽象了所有Spring內(nèi)部使用到的底層資源:File,URL,Classpath等火脉。

定義了3個(gè)判斷當(dāng)前資源狀態(tài)的方法:存在性(exists)、可讀性(isReadable)柒啤、是否處于打開狀態(tài)(isOpen)倦挂。另外,Resource接口還提供了不同資源到URL担巩、URI方援、File類型的轉(zhuǎn)換,以及獲取lastModified屬性涛癌、文件名(不帶路徑信息的文件名犯戏,getFilename())的方法。為了便于操作拳话,Resource 還提供了基于當(dāng)前資源創(chuàng)建一個(gè)相對資源的方法:createRelativeO先匪。在錯(cuò)誤處理中需要詳細(xì)地打印出錯(cuò)的資源文件,因而 Resource還提供了 getDescription()方法用于在錯(cuò)誤處理中的打印信息弃衍。

image-20200822143834013

不同來源的資源文件都有相應(yīng)的Resource實(shí)現(xiàn):文件(FileSystemResource),ClassPath資源(ClassPathResource)呀非,URL資源(UrlResource),InputStream資源(InputStreamResource),Byte數(shù)組(ByteArrayResource)等。

具體實(shí)現(xiàn)也很簡單岸裙,ClassPathResource是通過ClassLoader進(jìn)行讀取文件的:

image-20200822145454635

得到了配置流后猖败,就交給了XmlBeanDefinitionReader進(jìn)行解析。

image-20200822145716503
image-20200822145729279

在初始化父類的時(shí)候降允,忽略裝配一些類

image-20200822145953961

加載Bean

image
  1. 封裝資源文件恩闻。當(dāng)進(jìn)入XmlBeanDefinitionReader后首先對參數(shù)Resource使用EncodeResource類進(jìn)行封裝。
  2. 獲取輸入流拟糕。從Resource中獲取對應(yīng)的InputSttream并構(gòu)造InputSource判呕。
  3. 通過構(gòu)造的InputSource實(shí)例和Resource實(shí)例繼續(xù)調(diào)用方法doLoadBeanDefinitions
image-20200822152733034

EncodeedResource主要用于對資源文件的編碼進(jìn)行相應(yīng)的編碼處理送滞。

image-20200822154027396

如果設(shè)置了編碼屬性侠草,會(huì)使用相應(yīng)的編碼作為輸入流的編碼。

image.png

這個(gè)方法主要是將重新編碼的輸入流轉(zhuǎn)換為SAX的InputSource對象犁嗅,同時(shí)如果指定了編碼边涕,需要設(shè)置相關(guān)的屬性。


image.png

這個(gè)方法處理了兩件事情:

  • 加載XML文件褂微,得到對應(yīng)的Document.
  • 根據(jù)返回的Document注冊bean

XML的驗(yàn)證模式

XML文件的驗(yàn)證模式保證了XML文件的正確性功蜓,而比較常用的驗(yàn)證模式有兩種:DTD和XSD。

image-20200822181516391
image-20200822181600969

DTD

DTD(Document Type Dedfinition)即文檔類型定義宠蚂,是一種XML約束模式語言式撼,是XML文件的驗(yàn)證機(jī)制,屬于XML文件組成的一部分求厕。DTD是一種保證XML文檔格式正確的有效方法著隆,可以通過比較XML文檔和DTD文件來看文檔是否符合規(guī)范,元素和標(biāo)簽使用是否正確呀癣。一個(gè)DTD文檔包含:元素的定義規(guī)則美浦,元素間關(guān)系的定義規(guī)則,元素可以使用的屬性项栏,可以使用的實(shí)體或符號規(guī)則浦辨。

要使用DTD驗(yàn)證模式的時(shí)候需要在XML文件的頭部聲明:

image-20200822172452919

DTD文件里面是一些ENTITY節(jié)點(diǎn)

image-20200822172528742

XSD

XML Schema語言就是XSD(XML Schema Definition)。Xml Schema描述了XML文檔的結(jié)構(gòu)沼沈×鞒辏可以用一個(gè)指定的XML Schema來驗(yàn)證某個(gè)XML文檔,已檢查改XML文檔是否符合其要求列另。文檔設(shè)計(jì)者可以通過過XML Schema指定一個(gè)XML文檔所允許的結(jié)構(gòu)和內(nèi)容康吵,并可以據(jù)此檢查一個(gè)XML文檔是否是以有效的。XML Schema本身是一個(gè)XML文檔访递,他符合XML語法結(jié)構(gòu),可以使用通用的XML解析器解析它同辣。

image-20200822181110255

在使用XML Schema文檔對XML實(shí)例文檔進(jìn)行檢驗(yàn)拷姿,除了要聲明空間外(xmlns=....)惭载,還必須指定該名稱空間鎖對應(yīng)的XML Schema文檔的存儲(chǔ)位置。通過schemaLocation屬性來指定名稱空間所對一樣的XML Schema文檔的存儲(chǔ)位置响巢。它包含兩個(gè)部分描滔,一部分是名稱空間的URL,另一部分就是該名稱空間所表示的XML Schema文件位置或者URL地址踪古。

獲取Document

image-20200822181621954

調(diào)用了DocumentLoader接口的方法:

image-20200822181704320

這個(gè)接口只有一個(gè)實(shí)現(xiàn)類DefaultDocumentLoader

image-20200822182350576

BeanDefinitions

將配置文件轉(zhuǎn)換為Document后含长,就會(huì)根據(jù)Document對象進(jìn)行注冊Bean.

image-20200822182535309

注冊bean:

image-20200822183351796

首先通過反射獲取BeanDefinitionDocumentReader的對象。

image-20200822183516072

然后記錄下本次注冊前伏穆,已經(jīng)有多少個(gè)bean被注冊了拘泞。

然后調(diào)用documentReader對象進(jìn)行注冊。

image-20200822183726851

使用的還是默認(rèn)實(shí)現(xiàn)

image-20200822183745063

在使用documentReader進(jìn)行讀取時(shí)枕扫,首先讀取的是root節(jié)點(diǎn)陪腌。

image-20200822183936937

接下來就是解析的核心邏輯了:

image.png

首先處理profile

image-20200822184440549

解析bean就是這里了

image-20200822184809167
image-20200822185320840
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市烟瞧,隨后出現(xiàn)的幾起案子诗鸭,更是在濱河造成了極大的恐慌,老刑警劉巖参滴,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件强岸,死亡現(xiàn)場離奇詭異,居然都是意外死亡砾赔,警方通過查閱死者的電腦和手機(jī)蝌箍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來过蹂,“玉大人十绑,你說我怎么就攤上這事】嵘祝” “怎么了本橙?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長脆诉。 經(jīng)常有香客問我甚亭,道長,這世上最難降的妖魔是什么击胜? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任亏狰,我火速辦了婚禮,結(jié)果婚禮上偶摔,老公的妹妹穿的比我還像新娘暇唾。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布策州。 她就那樣靜靜地躺著瘸味,像睡著了一般。 火紅的嫁衣襯著肌膚如雪够挂。 梳的紋絲不亂的頭發(fā)上旁仿,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機(jī)與錄音孽糖,去河邊找鬼枯冈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛办悟,可吹牛的內(nèi)容都是我干的尘奏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼誉尖,長吁一口氣:“原來是場噩夢啊……” “哼罪既!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起铡恕,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤琢感,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后探熔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驹针,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年诀艰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了柬甥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡其垄,死狀恐怖苛蒲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绿满,我是刑警寧澤臂外,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站喇颁,受9級特大地震影響漏健,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜橘霎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一蔫浆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧姐叁,春花似錦瓦盛、人聲如沸洗显。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽墙懂。三九已至,卻和暖如春扮念,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碧库。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工柜与, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嵌灰。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓弄匕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親沽瞭。 傳聞我的和親對象是個(gè)殘疾皇子迁匠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355