[譯] Java Service Loader 對比 Spring Factories Loader

Java 和 Spring 都提供了實現模塊層的 IoC 的方式(譯者注:Inversion of Control 控制反轉)。二者實現的功能很相似,不過 Spring 提供的功能更靈活一些。

IoC 並不只限於解決模塊內類與類之間的依賴耦合問題,其一樣適用於模塊與模塊之間。OSGi 一直致力於這方面的工做。但其實 Java 和 Spring 都提供了對 IoC 的支持。html

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 的接口來記錄日誌,而具體的實現則交由工程類路徑中可用的實現類來執行。java

爲了使用 Service Loader,首先須要在類所在工程的類路徑下面創建 'META-INF/services' 目錄,而後根據接口名在該目錄建立一個文件。該文件的文件名必須是接口的徹底限定名,其內容是可用實現的限定名列表。例如,對於 ch.frankel.blog.serviceloader.Foo 這個接口,文件名應該是 META-INF/services/ch.frankel.blog.serviceloader.Foo,文件的內容多是以下這樣的:android

ch.frankel.blog.serviceloader.FooImpl1
ch.frankel.blog.serviceloader.FooImpl2
複製代碼

其中包含的類必須實現 ch.frankel.blog.serviceloader.Foo 接口。ios

使用 Service Loader 獲取實現類的代碼很是簡單:git

ServiceLoader<Foo> loader = ServiceLoader.load(Foo.class);
loader.iterator();
複製代碼

Service Loader 的 Spring 實現

核心的 Spring 庫以工廠模式集成了 Java 的 Service Loader。例如,下面的代碼假定工程內至少有一個可選的 Foo 接口的實現類:github

@Configuration
public class ServiceConfiguration {
    @Bean
    public ServiceListFactoryBean serviceListFactoryBean() {
        ServiceListFactoryBean serviceListFactoryBean = new ServiceListFactoryBean();
        serviceListFactoryBean.setServiceType(Foo.class);
        return serviceListFactoryBean;
    }
}
Object object = serviceListFactoryBean.getObject();
複製代碼

很明顯,從調用返回來看,須要進一步操做才能獲得正確格式的數據(注意:serviceListFactoryBean 是一個鏈表)。spring

Spring Factories Loader

除了集成 Java 的 Service Loader 以外,Spring 還提供了另外一種 IoC 的實現。其只須要添加一個簡單的配置文件,文件名必須爲 spring.factories 而且放到 META-INF 下。從代碼的角度看,這個文件經過靜態方法 SpringFactoriesLoader.loadFactories() 來讀取。Spring 的這個實現確實讓你吃驚。 調用的代碼不能再簡單了:後端

List<Foo> foos = SpringFactoriesLoader.loadFactories(Foo.class, null);
複製代碼

上面第二個可選參數是類加載器api

相對於 Java Service Loader,主要有兩方面的區別:

  1. 經過一個文件來配置是否比其餘方式更好,更可讀,更可維護,這取決於我的喜愛。
  2. spring.factories 中並無要求鍵是一個接口而且實現它的值。例如,Spring Boot 使用這種方法來初始化類實例:配置中鍵內容爲一個註解,如 org.springframework.boot.autoconfigure.EnableAutoConfiguration,而值是則能夠是標註了 @Configuration 註解的類。若是靈活使用,能夠去完成更多更復雜的設計。

這篇文章的資源能夠在 GitHub 的 Maven 格式下找到。

延伸閱讀:

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索