簡介
SPI(Service Provider Interface)服務提供接口,是指的一種服務發現機制,爲某個特定的接口尋找服務的實現。在大規模的軟件開發中經常採用這樣的機制,實現模塊之間基於接口編程,隱藏其實現細節,不同的服務提供商進行擴展實現,最終實現無需修改代碼即可調用,實現完全無代碼入侵。
使用
創建一個接口:
public interface TestSpiService {
void doSomething();
}
創建兩個實現類:
public class TestSpiServiceImpl1 implements TestSpiService {
@Override
public void doSomething() {
System.out.println("TestSpiServiceImpl1");
}
}
public class TestSpiServiceImpl2 implements TestSpiService {
@Override
public void doSomething() {
System.out.println("TestSpiServiceImpl2");
}
}
然後在src/main/resources/目錄下創建子目錄META-INF/services.創建一個以接口全限定名com.xll.spi.TestSpiService爲文件名的文件。 內容就是具體的實現類:
com.xll.spi.TestSpiServiceImpl1
com.xll.spi.TestSpiServiceImpl2
測試調用實現類;
public class Test {
public static void main(String[] args) {
ServiceLoader<TestSpiService> load = ServiceLoader.load(TestSpiService.class);
Iterator<TestSpiService> iterator = load.iterator();
while (iterator.hasNext()) {
TestSpiService service = iterator.next();
service.doSomething();
}
}
}
應用場景
SPI機制一般用在插件擴展的場景:比如說你開發的是一個給別人使用的開源框架,如果你想讓別人自己寫個插件,插到你的開源框架裏面來,擴展某個功能.
經典的思想體現:比如說jdbc.java定義了一套jdbc的接口,但是java是沒有提供jdbc的實現類.但是實際上項目跑的時候,要使用jdbc接口的哪些實現類呢?一般來說,我們要根據自己使用的數據庫,比如msyql,你就將mysql-jdbc-connector.jar,引入進來;oracle,你就將oracle-jdbc-connector.jar,引入進來。
在系統跑的時候,碰到你使用jdbc的接口,他會在底層使用你引入的那個jar中提供的實現類.
應用案例
dubbo 基於jdk的spi機制實現了自己的一套spi機制,讓用戶擴展dubbo的默認實現。 具體可以看dubbo的源碼。
還有比如說fastjson,你去看它的源碼,應該也是支持應用覆蓋它的原生實現類的。