- 原文地址:Java Service Loader vs. Spring Factories Loader
- 原文作者:Nicolas Frankel
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:HearFishle
- 校對者:Endone,ziyin feng
Java 和 Spring 都提供了實現模組層的 IoC 的方式(譯者注:Inversion of Control 控制反轉)。兩者實現的功能很類似,不過 Spring 提供的功能更靈活一些。
IoC 並不僅限於解決模組內類與類之間的依賴耦合問題,其同樣適用於模組與模組之間。OSGi 一直致力於這方面的工作。但其實 Java 和 Spring 都提供了對 IoC 的支援。
Java Service Loader
Java 本身提供了一種很簡便的方式來支援 IoC,它通過使用 [Service Loader] (https://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html) 來實現,其可以獲取到工程類路徑內指定介面的實現類。這使我們可以在執行期間獲知類路徑內包含哪些可用的實現類,從而做到介面定義和多個實現模組(JAR 包)之間的依賴解耦。
SLF4J 作為一個日誌框架正是使用了這個方法。SLF4J 本身只提供日誌操作介面,其他的日誌系統基於這些介面進行實現(如 Logback 和 Log4J 等)。使用者只需通過呼叫 SLF4J 的介面來記錄日誌,而具體的實現則交由工程類路徑中可用的實現類來執行。
為了使用 Service Loader,首先需要在類所在工程的類路徑下面建立 'META-INF/services' 目錄,然後根據介面名在該目錄建立一個檔案。該檔案的檔名必須是介面的完全限定名,其內容是可用實現的限定名列表。例如,對於 ch.frankel.blog.serviceloader.Foo
這個介面,檔名應該是 META-INF/services/ch.frankel.blog.serviceloader.Foo
,檔案的內容可能是如下這樣的:
ch.frankel.blog.serviceloader.FooImpl1
ch.frankel.blog.serviceloader.FooImpl2
複製程式碼
其中包含的類必須實現 ch.frankel.blog.serviceloader.Foo
介面。
使用 Service Loader 獲取實現類的程式碼非常簡單:
ServiceLoader<Foo> loader = ServiceLoader.load(Foo.class);
loader.iterator();
複製程式碼
Service Loader 的 Spring 實現
核心的 Spring 庫以工廠模式整合了 Java 的 Service Loader。例如,下面的程式碼假定工程內至少有一個可選的 Foo 介面的實現類:
@Configuration
public class ServiceConfiguration {
@Bean
public ServiceListFactoryBean serviceListFactoryBean() {
ServiceListFactoryBean serviceListFactoryBean = new ServiceListFactoryBean();
serviceListFactoryBean.setServiceType(Foo.class);
return serviceListFactoryBean;
}
}
Object object = serviceListFactoryBean.getObject();
複製程式碼
很明顯,從呼叫返回來看,需要進一步操作才能得到正確格式的資料(注意:serviceListFactoryBean 是一個連結串列)。
Spring Factories Loader
除了整合 Java 的 Service Loader 之外,Spring 還提供了另一種 IoC 的實現。其只需要新增一個簡單的配置檔案,檔名必須為 spring.factories
並且放到 META-INF
下。從程式碼的角度看,這個檔案通過靜態方法 SpringFactoriesLoader.loadFactories()
來讀取。Spring 的這個實現確實讓你吃驚。
呼叫的程式碼不能再簡單了:
List<Foo> foos = SpringFactoriesLoader.loadFactories(Foo.class, null);
複製程式碼
上面第二個可選引數是類載入器
相對於 Java Service Loader,主要有兩方面的區別:
- 通過一個檔案來配置是否比其他方式更好,更可讀,更可維護,這取決於個人喜好。
spring.factories
中並沒有要求鍵是一個介面並且實現它的值。例如,Spring Boot 使用這種方法來初始化類例項:配置中鍵內容為一個註解,如org.springframework.boot.autoconfigure.EnableAutoConfiguration
,而值是則可以是標註了@Configuration
註解的類。如果靈活使用,可以去完成更多更復雜的設計。
這篇文章的資源可以在 GitHub 的 Maven 格式下找到。
延伸閱讀:
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。