java中的SPI機制

<main>

<article>

1 SPI機制簡介

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

2 SPI具體約定

java spi的具體約定為:當服務的提供者,提供了服務接口的一種實現(xiàn)之后,在jar包的META-INF/services/目錄里同時創(chuàng)建一個以服務接口命名的文件。該文件里就是實現(xiàn)該服務接口的具體實現(xiàn)類。而當外部程序裝配這個模塊的時候,就能通過該jar包META-INF/services/里的配置文件找到具體的實現(xiàn)類名,并裝載實例化,完成模塊的注入。 基于這樣一個約定就能很好的找到服務接口的實現(xiàn)類,而不需要再代碼里制定。jdk提供服務實現(xiàn)查找的一個工具類:java.util.ServiceLoader

3 應用場景

1.common-logging apache最早提供的日志的門面接口。只有接口,沒有實現(xiàn)。具體方案由各提供商實現(xiàn), 發(fā)現(xiàn)日志提供商是通過掃描 META-INF/services/org.apache.commons.logging.LogFactory配置文件,通過讀取該文件的內(nèi)容找到日志提工商實現(xiàn)類。只要我們的日志實現(xiàn)里包含了這個文件,并在文件里制定 LogFactory工廠接口的實現(xiàn)類即可。
2.jdbc jdbc4.0以前, 開發(fā)人員還需要基于Class.forName("xxx")的方式來裝載驅(qū)動,jdbc4也基于spi的機制來發(fā)現(xiàn)驅(qū)動提供商了,可以通過META-INF/services/java.sql.Driver文件里指定實現(xiàn)類的方式來暴露驅(qū)動提供者.

4 案例說明

一個內(nèi)容管理系統(tǒng)有一個搜索模塊。是基于接口編程的。搜索的實現(xiàn)可能是基于文件系統(tǒng)的搜索,也可能是基于數(shù)據(jù)庫的搜索

接口定義如

[java] view plain copy print?

package my.xyz.spi;  
import java.util.List;  
public interface Search {  
   public List serch(String keyword);  
}

A公司采用文件系統(tǒng)搜索的方式實現(xiàn)了 Search接口,B公司采用了數(shù)據(jù)庫系統(tǒng)的方式實現(xiàn)了Search接口
A公司實現(xiàn)的類 com.A.spi.impl.FileSearch
B公司實現(xiàn)的類 com.B.spi.impl.DatabaseSearch

那么A公司發(fā)布 實現(xiàn)jar包時,則要在jar包中META-INF/services/my.xyz.spi.Search文件中寫下如下內(nèi)容

com.A.spi.impl.FileSearch

那么B公司發(fā)布 實現(xiàn)jar包時,則要在jar包中META-INF/services/my.xyz.spi.Search文件中寫下如下內(nèi)容

com.B.spi.impl.DatabaseSearch

[java] view plain copy print?

package com.xyz.factory;  
import java.util.Iterator;  
import java.util.ServiceLoader;  
import my.xyz.spi.Search;  
public class SearchFactory {  
    private SearchFactory() {  
    }  
    public static Search newSearch() {  
        Search search = null;  
        ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class);  
        Iterator<Search> searchs = serviceLoader.iterator();  
        if (searchs.hasNext()) {  
            search = searchs.next();  
        }  
        return search;  
    }  
} 
1.  package my.xyz.test;    
2.  import java.util.Iterator;    
3.  import java.util.ServiceLoader;    
4.  import com.xyz.factory.SearchFactory;    
5.  import my.xyz.spi.Search;    
6.  public class SearchTest {    
7.    public static void main(String[] args) {    
8.         Search search = SearchFactory.newSearch();    
9.         search.serch("java spi test");    
10.   }    
11.  }    

參考原文https://blog.csdn.net/sigangjun/article/details/79071850

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容