程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 淺析java的SPI機制

淺析java的SPI機制

編輯:關於JAVA

1 SPI機制簡介

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

2 SPI具體約定

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

3 應用場景

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文件裡指定實現類的方式來暴露驅動提供者.

4 案例說明

一個內容管理系統有一個搜索模塊。是基於接口編程的。搜索的實現可能是基於文件系統的搜索,也可能是基於數據庫的搜索

接口定義如下

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

A公司采用文件系統搜索的方式實現了 Search接口,B公司采用了數據庫系統的方式實現了Search接口

A公司實現的類  com.A.spi.impl.FileSearch

B公司實現的類  com.B.spi.impl.DatabaseSearch

查看本欄目

那麼A公司發布 實現jar包時,則要在jar包中META-INF/services/my.xyz.spi.Search文件中寫下如下內容

com.A.spi.impl.FileSearch

那麼B公司發布 實現jar包時,則要在jar包中META-INF/services/my.xyz.spi.Search文件中寫下如下內容

com.B.spi.impl.DatabaseSearch

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;  
    }  
}
package my.xyz.test;  
import java.util.Iterator;  
import java.util.ServiceLoader;  
import com.xyz.factory.SearchFactory;  
import my.xyz.spi.Search;  
public class SearchTest {  
    public static void main(String[] args) {  
        Search search = SearchFactory.newSearch();  
        search.serch("java spi test");  
    }  
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved