Java spi機制淺談

最近看到公司的一些框架和以前看到的開源的一些框架的一些服務發現和接入都採用了java的spi機制。javascript

因此簡單的總結下java spi機制的思想。html

 

咱們系統裏抽象的各個模塊,每每有不少不一樣的實現方案,好比日誌模塊的方案,xml解析模塊、jdbc模塊的方案等。面向的對象的設計裏,咱們通常推薦模塊之間基於接口編程,模塊之間不對實現類進行硬編碼。一旦代碼裏涉及具體的實現類,就違反了可拔插的原則,若是須要替換一種實現,就須要修改代碼。java

 

 

爲了實如今模塊裝配的時候能不在程序裏動態指明,這就須要一種服務發現機制。java spi就是提供這樣的一個機制:爲某個接口尋找服務實現的機制。有點相似IOC的思想,就是將裝配的控制權移到程序以外,在模塊化設計中這個機制尤爲重要。sql

 

java spi的具體約定以下 :

當服務的提供者,提供了服務接口的一種實現以後,在jar包的META-INF/services/目錄裏同時建立一個以服務接口命名的文件。該文件裏就是實現該服務接口的具體實現類。而當外部程序裝配這個模塊的時候,就能經過該jar包META-INF/services/裏的配置文件找到具體的實現類名,並裝載實例化,完成模塊的注入。 數據庫

基於這樣一個約定就能很好的找到服務接口的實現類,而不須要再代碼裏制定。apache

jdk提供服務實現查找的一個工具類:java.util.ServiceLoader編程

 

例子

1.common-loggingoracle

apache最先提供的日誌的門面接口。只有接口,沒有實現。具體方案由各提供商實現,發現日誌提供商是經過掃描 META-INF/services/org.apache.commons.logging.LogFactory配置文件,經過讀取該文件的內容找到日誌提工商實現類。只要咱們的日誌實現裏包含了這個文件,並在文件裏制定 LogFactory工廠接口的實現類便可。app

2.jdbc框架

jdbc4.0之前,開發人員還須要基於Class.forName("xxx")的方式來裝載驅動,jdbc4也基於spi的機制來發現驅動提供商了,能夠經過META-INF/services/java.sql.Driver文件裏指定實現類的方式來暴露驅動提供者。

3.本身編寫簡單例子

假設有一個內容搜索系統,分爲展現和搜索兩個模塊。展現和搜索基於接口編程。搜索的實現多是基於文件系統的搜索,也多是基於數據庫的搜索。實例代碼以下

Search.java: 搜索接口

Java代碼 

 收藏代碼

  1. package search;  
  2.   
  3. import java.util.List;  
  4.   
  5. import definition.Doc;  
  6.   
  7. public interface Search {  
  8.     List<Doc> search(String keyword);  
  9. }  

 

FileSearch.java:文件系統的搜索實現

Java代碼 

 收藏代碼

  1. package search;  
  2.   
  3. import java.util.List;  
  4.   
  5. import definition.Doc;  
  6.   
  7. public class FileSearch implements Search {  
  8.   
  9.     @Override  
  10.     public List<Doc> search(String keyword) {  
  11.         System.out.println("now use file system search. keyword:" + keyword);  
  12.         return null;  
  13.     }  
  14.   
  15. }  

 

DatabaseSearch.java

Java代碼 

 收藏代碼

  1. package search;  
  2.   
  3. import java.util.List;  
  4.   
  5. import definition.Doc;  
  6.   
  7. public class DatabaseSearch implements Search {  
  8.   
  9.     @Override  
  10.     public List<Doc> search(String keyword) {  
  11.         System.out.println("now use database search. keyword:" + keyword);  
  12.         return null;  
  13.     }  
  14.   
  15. }  

 

SearchTest.java

Java代碼 

 收藏代碼

  1. package search;  
  2.   
  3. import java.util.Iterator;  
  4. import java.util.ServiceLoader;  
  5.   
  6. public class SearchTest {  
  7.   
  8.     public static void main(String[] args) {  
  9.         ServiceLoader<Search> s = ServiceLoader.load(Search.class);  
  10.         Iterator<Search> searchs = s.iterator();  
  11.         if (searchs.hasNext()) {  
  12.             Search curSearch = searchs.next();  
  13.             curSearch.search("test");  
  14.         }  
  15.     }  
  16. }  

 

最後建立在META-INF/searvices/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的機制去查找服務的實現。

 

參考文獻:

http://docs.oracle.com/javase/1.4.2/docs/guide/jar/jar.html#Service%20Provider

相關文章
相關標籤/搜索