Spring 源碼導(dǎo)讀

java高級(jí)架構(gòu)師

做為Java開源世界的第一框架,Spring已經(jīng)成為事實(shí)上的Java EE開發(fā)標(biāo)準(zhǔn)Spring框架最根本的使命是簡(jiǎn)化Java開發(fā),因此學(xué)習(xí)寨腔、研究、掌握Spring框架成為每一位Java開發(fā)人員的必修課率寡。而閱讀源碼則是學(xué)習(xí)Spring的最好方式之一迫卢。

Spring里面最重要的特性就是Ioc,可能你還會(huì)說(shuō)aop冶共。其實(shí)aop的實(shí)現(xiàn)也是基于ioc乾蛤。Ioc(Inversion of Control)每界,即“控制反轉(zhuǎn)”,不是什么技術(shù)家卖,而是一種設(shè)計(jì)思想眨层。在Java開發(fā)中,Ioc意味著將你設(shè)計(jì)好的對(duì)象交給容器控制上荡,而不是傳統(tǒng)的在你的對(duì)象內(nèi)部直接控制趴樱。

關(guān)于Spring IOC源碼分析的文章網(wǎng)上很多,現(xiàn)在我就來(lái)另辟蹊徑榛臼。Spring Ioc的對(duì)象扭轉(zhuǎn)以及涉及到的核心接口來(lái)分析一下它的源碼實(shí)現(xiàn)伊佃。

我把Spring Ioc的對(duì)象轉(zhuǎn)換分為以下4個(gè)步驟:

Resource -> BeanDefinition -> BeanWrapper -> Object

1 Resource

Resouce 其實(shí)是一個(gè)接口,代表的是資源沛善,在計(jì)算機(jī)里面從一個(gè)地方移動(dòng)到另外一個(gè)地方所需要的東西就是數(shù)據(jù)流航揉,所以 Resource 實(shí)現(xiàn)了 InputStreamSource 接口,通過(guò) InputStreamSource 接口可以獲取到 Inputstream金刁,這樣就可以讀取不同的 Bean 定義了帅涂。

publicinterface InputStreamSource {

? ?InputStream getInputStream() throws IOException;

}

Spring可以定義不同類型的bean,最后都可以封裝成Resource通過(guò)IO流進(jìn)行讀取尤蛮。 Spring可以定義類型的bean對(duì)象:

XML:這是Spring最開始定義bean的形式

Annotation :由于通過(guò)XML定義bean的繁瑣媳友,Spring進(jìn)行了改進(jìn)可以通過(guò)@Component以及基于它的注解來(lái)定義bean。例如:@Service产捞,@Controller等等醇锚,它們都可以定義bean ,只不過(guò)語(yǔ)義更加明確坯临。

Class:通過(guò)@Configuration與@Bean注解定義焊唬,@Configuration代理xml資源文件,而@Bean代替標(biāo)簽看靠。

Properties/yml:通過(guò) @EnableConfigurationProperties 與 @ConfigurationProperties 來(lái)定義bean赶促。這種形式在Spring boot自動(dòng)注入里面大量使用。

2挟炬、BeanDefinition

望文生義鸥滨,很顯示這個(gè)是 Bean 對(duì)象的定義。 Spring通過(guò)不同形式來(lái)定義bean谤祖,最終會(huì)把這些定義轉(zhuǎn)化成BeanDefinition 保存在Spring容器當(dāng)中進(jìn)行依賴注入婿滓。下面我們來(lái)看一下BeanDefinition的接口定義。

這個(gè)接口的定義很復(fù)雜但是粥喜,對(duì)于初始理解spring ioc空幻,只需要關(guān)心兩個(gè)方法。

getConstructorArgumentValues:獲取構(gòu)造器注入定義的參數(shù)容客。

getPropertyValues:獲取setter注入定義的參數(shù)秕铛。

所以Spring支持構(gòu)造器注入與setter依賴注入约郁。

3、BeanWapper

其實(shí)什么是依賴注入但两,簡(jiǎn)單來(lái)說(shuō)就是Spring幫我們創(chuàng)建對(duì)象鬓梅。把創(chuàng)建對(duì)象寫死在Java文件變成了通過(guò)不同的Spring配置可以注入不同的值。創(chuàng)建對(duì)象的職責(zé)由Java文件變成了Spring配置文件谨湘。

下面我就問(wèn)一個(gè)簡(jiǎn)單的問(wèn)題绽快,如何創(chuàng)建對(duì)象〗衾可能大家呵呵一笑坊罢,創(chuàng)建對(duì)象這還不簡(jiǎn)單。

其實(shí) Spring 也是這樣來(lái)創(chuàng)建對(duì)象的擅耽,不信講看?: (入口方法?BeanFactory#getBean)

AbstractAutowireCapableBeanFactory#createBeanInstance() :通過(guò)反射Constructor調(diào)用配置的無(wú)參或者有參來(lái)創(chuàng)建對(duì)象實(shí)例活孩。通過(guò)BeanDefinition#getConstructorArgumentValues 獲取,并返回 BeanWrapper 對(duì)象乖仇。

AbstractAutowireCapableBeanFactory#populateBean():憾儒,獲取到定義的bean生成的所有的定義的setter注入的屬性(BeanDefinition#getPropertyValues),然后遍歷些這些屬性乃沙,通過(guò)內(nèi)省獲取到對(duì)象所有的 屬性描述器(PropertyDescriptor)起趾,獲取到,屬性的PropertyDescriptor#getWriteMethod方法警儒,也就是setter方法训裆,依賴注入值。如果是普通屬性或者一些復(fù)雜對(duì)象蜀铲,比如普通屬性String, int, long或者classpath:*轉(zhuǎn)換為Resource復(fù)雜對(duì)象等等边琉,直接注入即可;對(duì)于引用類型對(duì)象,繼續(xù)依賴注入直到所有的屬性是普通屬性為止蝙茶。

AbstractAutowireCapableBeanFactory#initializeBean():調(diào)用 Spring 自定義的初始化方法比如:BeanPostProcessor 擴(kuò)展以及 init-method。

實(shí)例化對(duì)象返回BeanWrapper诸老,其實(shí)是為了依賴注入服務(wù)也就是上面的第二步隆夯。 這個(gè)接口的功能還是很復(fù)雜的,它繼承了 4 個(gè)接口别伏。

TypeConverter

PropertyEditorRegistry

PropertyAccessor

ConfigurablePropertyAccessor

下面就來(lái)分別介紹一下這些接口的功能蹄衷。

3.1 TypeConverter

下面就是這個(gè)接口的定義。

它的作用就是自動(dòng)類型轉(zhuǎn)換厘肮,因?yàn)镾pring作得太無(wú)感知了愧口。你也許還沒(méi)有感覺(jué)到它的存在。沒(méi)關(guān)系类茂,我提示一下你應(yīng)該就會(huì)明白耍属。比如托嚣,聲明一個(gè)用戶對(duì)象這個(gè)對(duì)象既有String類型的名稱,又有Int類型的年齡厚骗。Spring怎么知道屬性的類型呢示启?這個(gè)就是 Spring的自動(dòng)類型轉(zhuǎn)換。關(guān)于Spring的自動(dòng)類型轉(zhuǎn)換?我在之前就已經(jīng)分析過(guò)了领舰。

3.2 PropertyEditorRegistry

這個(gè)接口主要的作用是注冊(cè)屬性修改器(PropertyEditor)夫嗓,這個(gè)是 Java 內(nèi)省里面的機(jī)制。

一般通過(guò)繼承 java.beans.PropertyEditorSupport 來(lái)實(shí)現(xiàn)自定義的類型轉(zhuǎn)換冲秽。在 Spring 內(nèi)部有大量的實(shí)現(xiàn)舍咖,如下圖所示

3.3 PropertyAccessor

PropertyAccessor這個(gè)接口是判斷對(duì)象中的某個(gè)屬性是否可讀/可寫,并且可以定入或者讀取某個(gè)屬性的值锉桑。從這個(gè)接口定義我們可以看出排霉,它的使用其實(shí)就是真正用來(lái)依賴注入的。然后調(diào)用屬性操作的寫入操作刨仑,完全依賴注入郑诺。

3.4 ConfigurablePropertyAccessor

這個(gè)接口的功能和PropertyEditorRegistry接口一樣,只不過(guò)后者是通過(guò)java內(nèi)省來(lái)進(jìn)行類型自動(dòng)轉(zhuǎn)換杉武,而ConfigurablePropertyAccessor接口是通過(guò)Spring自己定義的org.springframework.core.convert.ConversionService來(lái)作類型轉(zhuǎn)換類型轉(zhuǎn)換辙诞。在Spring中默認(rèn)使用的DefaultConversionService來(lái)作自動(dòng)類型轉(zhuǎn)換支持,并且內(nèi)部還添加了很多默認(rèn)的類型轉(zhuǎn)換轻抱。

關(guān)于Spring的自動(dòng)類型轉(zhuǎn)換?我在之前就已經(jīng)分析過(guò)了飞涂。和java內(nèi)省的原理是一樣的。

3.5 BeanWrapper

這個(gè)接口就挺簡(jiǎn)單了祈搜,通過(guò)實(shí)現(xiàn)了上面的幾個(gè)接口具有了依賴注入较店、類型轉(zhuǎn)換注冊(cè)(java 內(nèi)省或者Spring自定義的自動(dòng)類型轉(zhuǎn)換)。然后這個(gè)接口的主要的作用就是通過(guò)調(diào)用getWrappedInstance方法獲取到當(dāng)前實(shí)例對(duì)象容燕,提供給屬性的writer方法進(jìn)行依賴注入梁呈。

writeMethod.invoke(getWrappedInstance(),value);

1

4、總結(jié)

讓我們?cè)賮?lái)看一下Spring的對(duì)象扭轉(zhuǎn)過(guò)過(guò)程:

Resource -> BeanDefinition -> BeanWrapper -> Object

相信基于以上的講解蘸秘,大家對(duì)于上面的過(guò)程能夠理解Spring IOC的項(xiàng)目過(guò)程官卡。在Spring 進(jìn)行 依賴注入的時(shí)候,首先把這種資源轉(zhuǎn)化成Resource抽象醋虏,通過(guò)里面的IO流讀取定義的bean寻咒。然后再轉(zhuǎn)化成BeanDefinitioin,里面定義了包括構(gòu)造器注入颈嚼,以及setter注入的定義毛秘。最后通過(guò)BeanWrapper這個(gè)接口,首先獲取定義的構(gòu)造器注入屬性,通過(guò)反射中的Constructor來(lái)創(chuàng)建對(duì)象叫挟〖璩祝基于這個(gè)對(duì)象霞揉,通過(guò)java里面的內(nèi)省機(jī)制獲取到定義屬性的屬性描述器(PropertyDescriptor)适秩,調(diào)用屬性的寫入方法完成依賴注入,最后再調(diào)用Spring的自定義初始化邏輯骤公,主要包括以下三個(gè)擴(kuò)展點(diǎn):

BeanPostProcess扬跋,Spring aop就是基于此擴(kuò)展钦听。

Init-method,可以在?bean?標(biāo)簽通過(guò) init-method定義垒棋,也可以實(shí)現(xiàn)InitializingBean

XXXAware叼架,Spring容器感知類衣撬,可以在bean里面獲取到 Spring容器的內(nèi)部屬性具练。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市哥遮,隨后出現(xiàn)的幾起案子占键,更是在濱河造成了極大的恐慌元潘,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牲距,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡咖摹,警方通過(guò)查閱死者的電腦和手機(jī)难述,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門胁后,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)攀芯,“玉大人,你說(shuō)我怎么就攤上這事殖演∨烤茫” “怎么了阻星?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵滥酥,是天一觀的道長(zhǎng)畦幢。 經(jīng)常有香客問(wèn)我,道長(zhǎng)宇葱,這世上最難降的妖魔是什么瘦真? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任黍瞧,我火速辦了婚禮诸尽,結(jié)果婚禮上印颤,老公的妹妹穿的比我還像新娘您机。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布咸产。 她就那樣靜靜地躺著,像睡著了一般仲闽。 火紅的嫁衣襯著肌膚如雪脑溢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天赖欣,我揣著相機(jī)與錄音屑彻,去河邊找鬼顶吮。 笑死酱酬,一個(gè)胖子當(dāng)著我的面吹牛云矫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼腮敌!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤捌木,失蹤者是張志新(化名)和其女友劉穎油坝,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刨裆,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡澈圈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帆啃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瞬女。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖努潘,靈堂內(nèi)的尸體忽然破棺而出诽偷,到底是詐尸還是另有隱情盯桦,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布渤刃,位于F島的核電站,受9級(jí)特大地震影響贴膘,放射性物質(zhì)發(fā)生泄漏卖子。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一刑峡、第九天 我趴在偏房一處隱蔽的房頂上張望洋闽。 院中可真熱鬧,春花似錦突梦、人聲如沸诫舅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刊懈。三九已至,卻和暖如春娃闲,著一層夾襖步出監(jiān)牢的瞬間虚汛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工皇帮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卷哩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓属拾,卻偏偏與公主長(zhǎng)得像将谊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子渐白,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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