天天看點

《SpringBoot揭秘:快速建構微服務體系》—第2章2.3節 了解一點兒JavaConfig

本節書摘來自華章出版社《springboot揭秘:快速建構微服務體系》一書中的第2章,第2.2節了解一點兒javaconfig,作者王福強,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

2.3 了解一點兒javaconfig

java 5的推出,加上當年基于純java annotation的依賴注入架構guice的出現,使得spring架構及其社群也“順應民意”,推出并持續完善了基于java代碼和annotation元資訊的依賴關系綁定描述方式,即javaconfig項目。

基于javaconfig方式的依賴關系綁定描述基本上映射了最早的基于xml的配置方式,比如:

(1)表達形式層面

基于xml的配置方式是這樣的:

《SpringBoot揭秘:快速建構微服務體系》—第2章2.3節 了解一點兒JavaConfig
《SpringBoot揭秘:快速建構微服務體系》—第2章2.3節 了解一點兒JavaConfig

而基于javaconfig的配置方式是這樣的:

@configuration

public class mockconfiguration{

}

任何一個标注了@configuration的java類定義都是一個javaconfig配置類。

(2)注冊bean定義層面

基于xml的配置形式是這樣的:

而基于javaconfig的配置形式是這樣的:

任何一個标注了@bean的方法,其傳回值将作為一個bean定義注冊到spring的ioc容器,方法名将預設成為該bean定義的id。

(3)表達依賴注入關系層面

為了表達bean與bean之間的依賴關系,在xml形式中一般是這樣的:

而在javaconfig中則是這樣的:

如果一個bean的定義依賴其他bean,則直接調用對應javaconfig類中依賴bean的建立方法就可以了。

在javaconfig形式的依賴注入過程中,我們使用方法調用的形式注入依賴,如果這個方法傳回的對象執行個體隻被一個bean依賴注入,那也還好,如果多于一個bean需要依賴這個方法調用傳回的對象執行個體,那是不是意味着我們就會建立多個同一類型的對象執行個體?

從代碼表述的邏輯來看,直覺上應該是會建立多個同一類型的對象執行個體,但實際上最終結果卻不是這樣,依賴注入的都是同一個singleton的對象執行個體,那這是如何做到的?

筆者一開始以為spring架構會通過解析javaconfig的代碼結構,然後通過解析器轉換加上反射等方式完成這一目的,但實際上spring架構的設計和實作者采用了另一種更通用的方式,這在spring的參考文檔中有說明,即通過攔截配置類的方法調用來避免多次初始化同一類型對象的問題,一旦擁有攔截邏輯的子類發現目前方法沒有對應的類型執行個體時才會去請求父類的同一方法來初始化對象執行個體,否則直接傳回之前的對象執行個體。

是以,原來spring ioc容器中有的特性(features)在javaconfig中都可以表述,隻是換了一種形式而已,而且,通過聲明相應的java annotation反而“内聚”一處,變得更加簡潔明了了。

2.3.1 那些高曝光率的annotation

至于@configuration,我想前面已經提及過了,這裡不再贅述,下面我們看幾個其他比較常見的annotation,便于為後面更好地了解springboot架構的奧秘做準備。

@componentscan

@componentscan對應xml配置形式中的元素,用于配合一些元資訊java annotation,比如@component和@repository等,将标注了這些元資訊annotation的bean定義類批量采集到spring的ioc容器中。

我們可以通過basepackages等屬性來細粒度地定制@componentscan自動掃描的範圍,如果不指定,則預設spring架構實作會從聲明@componentscan所在類的package進行掃描。

@componentscan是springboot架構魔法得以實作的一個關鍵元件,大家可以重點關注,我們後面還會遇到它。

@propertysource與@propertysources

@propertysource用于從某些地方加載*.properties檔案内容,并将其中的屬性加載到ioc容器中,便于填充一些bean定義屬性的占位符(placeholder),當然,這需要propertysourcesplaceholderconfigurer的配合。

如果我們使用java 8或者更高版本開發(本書寫作期間java 9還沒釋出),那麼,我們可以并行聲明多個@propertysource:

如果我們使用低于java 8版本的java開發spring應用,又想聲明多個@propertysource,則需要借助@propertysources的幫助了:

@import與@importresource

在xml形式的配置中,我們通過的形式将多個分開的容器配置合到一個配置中,在javaconfig形式的配置中,我們則使用@import這個annotation完成同樣目的:

@import隻負責引入javaconfig形式定義的ioc容器配置,如果有一些遺留的配置或者遺留系統需要以xml形式來配置(比如dubbo架構),我們依然可以通過@importresource将它們一起合并到目前javaconfig配置的容器中: