做為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)部屬性具练。