<main>
<article>
1 SPI機(jī)制簡介
SPI的全名為Service Provider Interface.大多數(shù)開發(fā)人員可能不熟悉羞秤,因?yàn)檫@個(gè)是針對廠商或者插件的玖喘。在java.util.ServiceLoader的文檔里有比較詳細(xì)的介紹。簡單的總結(jié)下java spi機(jī)制的思想。我們系統(tǒng)里抽象的各個(gè)模塊,往往有很多不同的實(shí)現(xiàn)方案,比如日志模塊的方案红伦,xml解析模塊、jdbc模塊的方案等淀衣。面向的對象的設(shè)計(jì)里昙读,我們一般推薦模塊之間基于接口編程,模塊之間不對實(shí)現(xiàn)類進(jìn)行硬編碼膨桥。一旦代碼里涉及具體的實(shí)現(xiàn)類蛮浑,就違反了可拔插的原則,如果需要替換一種實(shí)現(xiàn)国撵,就需要修改代碼陵吸。為了實(shí)現(xiàn)在模塊裝配的時(shí)候能不在程序里動(dòng)態(tài)指明,這就需要一種服務(wù)發(fā)現(xiàn)機(jī)制介牙。 java spi就是提供這樣的一個(gè)機(jī)制:為某個(gè)接口尋找服務(wù)實(shí)現(xiàn)的機(jī)制壮虫。有點(diǎn)類似IOC的思想,就是將裝配的控制權(quán)移到程序之外环础,在模塊化設(shè)計(jì)中這個(gè)機(jī)制尤其重要囚似。
2 SPI具體約定
java spi的具體約定為:當(dāng)服務(wù)的提供者,提供了服務(wù)接口的一種實(shí)現(xiàn)之后线得,在jar包的META-INF/services/目錄里同時(shí)創(chuàng)建一個(gè)以服務(wù)接口命名的文件饶唤。該文件里就是實(shí)現(xiàn)該服務(wù)接口的具體實(shí)現(xiàn)類。而當(dāng)外部程序裝配這個(gè)模塊的時(shí)候贯钩,就能通過該jar包META-INF/services/里的配置文件找到具體的實(shí)現(xiàn)類名募狂,并裝載實(shí)例化办素,完成模塊的注入。 基于這樣一個(gè)約定就能很好的找到服務(wù)接口的實(shí)現(xiàn)類祸穷,而不需要再代碼里制定性穿。jdk提供服務(wù)實(shí)現(xiàn)查找的一個(gè)工具類:java.util.ServiceLoader
3 應(yīng)用場景
1.common-logging apache最早提供的日志的門面接口。只有接口雷滚,沒有實(shí)現(xiàn)需曾。具體方案由各提供商實(shí)現(xiàn), 發(fā)現(xiàn)日志提供商是通過掃描 META-INF/services/org.apache.commons.logging.LogFactory配置文件祈远,通過讀取該文件的內(nèi)容找到日志提工商實(shí)現(xiàn)類呆万。只要我們的日志實(shí)現(xiàn)里包含了這個(gè)文件,并在文件里制定 LogFactory工廠接口的實(shí)現(xiàn)類即可车份。
2.jdbc jdbc4.0以前谋减, 開發(fā)人員還需要基于Class.forName("xxx")的方式來裝載驅(qū)動(dòng),jdbc4也基于spi的機(jī)制來發(fā)現(xiàn)驅(qū)動(dòng)提供商了躬充,可以通過META-INF/services/java.sql.Driver文件里指定實(shí)現(xiàn)類的方式來暴露驅(qū)動(dòng)提供者.
4 案例說明
一個(gè)內(nèi)容管理系統(tǒng)有一個(gè)搜索模塊逃顶。是基于接口編程的。搜索的實(shí)現(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)搜索的方式實(shí)現(xiàn)了 Search接口,B公司采用了數(shù)據(jù)庫系統(tǒng)的方式實(shí)現(xiàn)了Search接口
A公司實(shí)現(xiàn)的類 com.A.spi.impl.FileSearch
B公司實(shí)現(xiàn)的類 com.B.spi.impl.DatabaseSearch
那么A公司發(fā)布 實(shí)現(xiàn)jar包時(shí)霸褒,則要在jar包中META-INF/services/my.xyz.spi.Search文件中寫下如下內(nèi)容
com.A.spi.impl.FileSearch
那么B公司發(fā)布 實(shí)現(xiàn)jar包時(shí)伴找,則要在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