最近看到公司的一些框架和之前看到的開源的一些框架的一些服務發現和存取都採用了java的spi機制。
所以簡單的總結下java spi機制的想法。
我們系統裡抽象的各個模組,往往有很多不同的實作方案,像是日誌模組的方案,xml解析模組、jdbc模組的方案等。在面向的物件的設計裡,我們一般推薦模組之間是基於介面程式,模組之間不對實作類別進行硬編碼。一旦程式碼裡涉及具體的實現類,就違反了可拔插的原則,如果需要替換一種實現,就需要修改程式碼。
為了實現在模組組裝的時候能不在程式裡動態指明,這就需要一種服務發現機制。 java spi就是提供這樣的一個機制:為某個介面尋找服務實作的機制。有點類似IOC的思想,就是將組裝的控制權移到程式之外,在模組化設計中這個機制尤其重要。
當服務的提供者,提供了服務介面的一種實作之後,在jar套件的META-INF/services /目錄裡同時建立一個以服務介面命名的檔案。該文件裡就是實作該服務介面的具體實作類別。而當外部程式組裝這個模組的時候,就能透過該jar包META-INF/services/裡的設定檔找到具體的實作類別名,並裝載實例化,完成模組的注入。
基於這樣一個約定就能很好的找到服務介面的實作類,而不需要再程式碼裡制定。
jdk提供服務實作尋找的工具類別:java.util.ServiceLoader
1.common-logging
apache最早提供的日誌的門面介面。只有接口,沒有實作。具體方案由各提供者實現,發現日誌提供者是透過掃描 META-INF/services/org.apache.commons.logging.LogFactory設定文件,透過讀取該文件的內容找到日誌提工商實作類別。只要我們的日誌實作裡包含了這個文件,並在文件裡制定 #LogFactory工廠介面的實作類別即可。
2.jdbc
jdbc4.0以前,開發人員還需要基於Class.forName("xxx")的方式來裝載驅動,jdbc4也基於spi的機制來發現驅動提供者了,可以透過META-INF/services/java.sql.Driver文件裡指定實作類別的方式來暴露驅動提供者。
3.自己寫簡單範例
假設有一個內容搜尋系統,分成展示和搜尋兩個模組。展示和搜尋基於介面程式設計。搜尋的實作可能是基於檔案系統的搜索,也可能是基於資料庫的搜尋。實例程式碼如下
Search.java: 搜尋介面
package search; import java.util.List; import definition.Doc; public interface Search { List<Doc> search(String keyword); }
#FileSearch.java:檔案系統的搜尋實作
package search; import java.util.List; import definition.Doc; public class FileSearch implements Search { @Override public List<Doc> search(String keyword) { System.out.println("now use file system search. keyword:" + keyword); return null; } }
DatabaseSearch.java
package search; import java.util.List; import definition.Doc; public class DatabaseSearch implements Search { @Override public List<Doc> search(String keyword) { System.out.println("now use database search. keyword:" + keyword); return null; } }
SearchTest.java
package search; import java.util.Iterator; import java.util.ServiceLoader; public class SearchTest { public static void main(String[] args) { ServiceLoader<Search> s = ServiceLoader.load(Search.class); Iterator<Search> searchs = s.iterator(); if (searchs.hasNext()) { Search curSearch = searchs.next(); curSearch.search("test"); } } }
最後建立在META-INF/services/search.Search檔案。
當search.Search檔案內容是"search.FileSearch"時,程式輸出是:
now use file system search. keyword:test
當search.Search檔案內容是"search.DatabaseSearch"時,程式輸出為:
now use database search. keyword:test
可以看出SearchTest裡沒有任何和具體實作有關的程式碼,而是基於spi的機制去尋找服務的實作
以上是Java spi機制的簡單介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!