1. 程式人生 > >Spring Boot擴充套件機制:圖文深入分析Spring Factories機制

Spring Boot擴充套件機制:圖文深入分析Spring Factories機制

在Spring Boot中有一種非常解耦的擴充套件機制:Spring Factories。這種擴充套件機制實際上是仿照Java中的SPI擴充套件機制來實現的。

Java SPI機制

SPI的全名為Service Provider Interface.大多數開發人員可能不熟悉,因為這個是針對廠商或者外掛的。在java.util.ServiceLoader的文件裡有比較詳細的介紹。簡單的總結下java spi機制的思想。我們系統裡抽象的各個模組,往往有很多不同的實現方案,比如日誌模組的方案,xml解析模組、jdbc模組的方案等。面向的物件的設計裡,我們一般推薦模組之間基於介面程式設計,模組之間不對實現類進行硬編碼。一旦程式碼裡涉及具體的實現類,就違反了可拔插的原則,如果需要替換一種實現,就需要修改程式碼。為了實現在模組裝配的時候能不在程式裡動態指明,這就需要一種服務發現機制。 java spi就是提供這樣的一個機制:為某個介面尋找服務實現的機制。有點類似IOC的思想,就是將裝配的控制權移到程式之外,在模組化設計中這個機制尤其重要。

Java SPI約定

java spi的具體約定為:當服務的提供者,提供了服務介面的一種實現之後,在jar包的META-INF/services/目錄裡同時建立一個以服務介面命名的檔案。該檔案裡就是實現該服務介面的具體實現類。而當外部程式裝配這個模組的時候,就能通過該jar包META-INF/services/裡的配置檔案找到具體的實現類名,並裝載例項化,完成模組的注入。 基於這樣一個約定就能很好的找到服務介面的實現類,而不需要再程式碼裡制定。jdk提供服務實現查詢的一個工具類:java.util.ServiceLoader

Spring Boot中的SPI機制

在Spring中也有一種類似與Java SPI的載入機制。它在META-INF/spring.factories檔案中配置介面的實現類名稱,然後在程式中讀取這些配置檔案並例項化。這種自定義的SPI機制是Spring Boot Starter實現的基礎。

spring.factories檔案

Spring Factories實現原理

spring-core包裡定義了SpringFactoriesLoader類,這個類實現了檢索META-INF/spring.factories檔案,並獲取指定介面的配置的功能。在這個類中定義了兩個對外的方法:

loadFactories。根據介面類獲取其實現類的例項,這個方法返回的是物件列表。

loadFactoryNames。根據介面獲取其介面類的名稱,這個方法返回的是類名的列表。

上面的兩個方法的關鍵都是從指定的ClassLoader中獲取spring.factories檔案,並解析得到類名列表,具體程式碼如下圖。

載入factories檔案

從程式碼中我們可以知道,在這個方法中會遍歷整個ClassLoader中所有jar包下的spring.factories檔案。也就是說我們可以在自己的jar中配置spring.factories檔案,不會影響到其它地方的配置,也不會被別人的配置覆蓋。

spring.factories的是通過Properties解析得到的,所以我們在寫檔案中的內容都是安裝下面這種方式配置的:

com.xxx.interface=com.xxx.classname

如果一個介面希望配置多個實現類,可以使用','進行分割。

對於loadFactories方法而言,在獲取類列表的基礎上,還有進行例項化的過程。

例項化過程

從這段程式碼中我們可以知道,它只支援沒有引數的建構函式。

Spring Factories在Spring Boot中的應用

在Spring Boot的很多包中都能夠找到spring.factories檔案,接下來我們以spring-boot包為例進行介紹。

spring.factories檔案內容

圖中展示了spring-boot中的spring.factories中的部分配置資訊。

日常工作中如何使用Spring Factories

在日常工作中,我們可能需要實現一些SDK或者Spring Boot Starter給被人使用,這個使用我們就可以使用Factories機制。Factories機制可以讓SDK或者Starter的使用只需要很少或者不需要進行配置,只需要在服務中引入我們的jar包。