SPI機制深入分析
概要
SPI全稱是Service Provider Interface. 大多數開發人員可能不熟悉,因為這個機制是針對第三方廠商或者外掛來提供服務的。SPI機制是jdk中java.util.ServiceLoader提供的,後面我們會詳細介紹。
一般我們在做開發的時候,都是抽象各個模組,然後有很多的實現方案,比如日誌模組、xml解析模組、jdbc模組等。在物件導向設計裡,我們一般推薦模組之間最好是基於介面程式設計,而不對具體的實現進行硬編碼。因為一旦程式碼改動涉及到具體的實現類,就違反了可插拔的原則。為了實現模組裝配的時候不在程式裡動態指明,就需要一種服務發現機制。而Java SPI就提供了這樣的一種機制:為某個介面尋找服務實現的機制。這個有點類似與IOC的思想,就是將裝配的控制權移交到程式之外
什麼是SPI
SPI是JDK內建的一種服務提供發現機制。目前市面上有很多框架都是用它來做服務的擴充套件發現。簡單來說,它是一種動態替換發現的機制。舉個簡單的例子,我們想在執行時動態給它新增實現,你只需要新增一個實現,然後把新的實現描述給JDK知道就行了。
實現SPI需要遵循的標準
我們如何去實現一個標準的SPI發現機制呢?其實很簡單,只需要滿足以下提交就行了
需要在classpath下建立一個目錄,該目錄命名必須是:META-INF/service
在該目錄下建立一個properties檔案,該檔案需要滿足以下幾個條件
2.1 檔名必須是擴充套件的介面的全路徑名稱
2.2 檔案內部描述的是該擴充套件介面的所有實現類
2.3 檔案的編碼格式是UTF-8
通過java.util.ServiceLoader的載入機制來發現
程式碼演示
程式碼結構
程式碼說明
我們定義了一個介面叫IHelloService, 介面中有一個方法
public interface IHelloService {
void sayHello();
}
接著定義了兩個實現類,一個是通過文字的方式來問候,另一個是通過表情的方式來問候,我們來看一下這兩個實現類的程式碼:
public class FaceHelloServiceImpl implements IHelloService{
public void sayHello() {
System.out.println("say hello with face:^_^");
}
}
public class TextHelloServiceImp implements IHelloService{
public void sayHello() {
System.out.println("say hello with text:你好");
}
}
以上就是核心程式碼了,接著來看一下resources目錄下的檔案,按照上面第二點說的要實現SPI需要滿足的格式:
1. resources/META-INF/service。
2. 檔名要以擴充套件介面的全路徑名:com.gupao.spi.demo.hello.IHelloService.properties
3. 該檔案的內容如下
com.gupao.spi.demo.hello.impl.FaceHelloServiceImpl
com.gupao.spi.demo.hello.impl.TextHelloServiceImp
最後就是呼叫的程式碼了
public class SPIMain
{
public static void main(String[] args) {
ServiceLoader<IHelloService> loader=ServiceLoader.load(IHelloService.class);
for (IHelloService hi:loader){
hi.sayHello();
}
}
}
通過SPIMain方法,就可以分別輸出
say hello with face:^_^
say hello with text:你好
這樣就實現了一個簡單的SPI的實現
SPI的實際應用
其實SPI在很多地方有應用,可能大家都沒有關注,最常用的就是JDBC驅動,我們來看看是怎麼應用的
JDK本身提供了資料訪問的api。在java.sql這個包裡面
我們在連線資料庫的時候,一定需要用到java.sql.Driver這個介面對吧。然後我好奇的去看了下java.sql.Driver的原始碼,發現Driver並沒有實現,而是提供了一套標準的api介面。大家有興趣可以去看看
因為我們在實際應用中用的比較多的是mysql,所以我去mysql的包裡面看到一個如下的目錄結構
看到了嗎? 目錄結構是不是符合SPI的定義?我懷著好奇心,開啟了java.sql.Driver這個檔案
這個檔案裡面寫的就是mysql的驅動實現。我恍然大悟,原來通過SPI機制把java.sql.Driver和mysql的驅動做了整合。這樣就達到了各個資料庫廠商自己去實現資料庫連線,jdk本身不關心你怎麼實現。
SPI的缺點
JDK標準的SPI會一次性載入例項化擴充套件點的所有實現,什麼意思呢?就是如果你在META-INF/service下的檔案裡面加了N個實現類,那麼JDK啟動的時候都會一次性全部載入。那麼如果有的擴充套件點實現初始化很耗時或者如果有些實現類並沒有用到,那麼會很浪費資源
如果擴充套件點載入失敗,會導致呼叫方報錯,而且這個錯誤很難定位到是這個原因
相關文章
- SPI機制
- 溫習 SPI 機制 (Java SPI 、Spring SPI、Dubbo SPI)JavaSpring
- Java 的 SPI 機制Java
- Java的SPI機制Java
- Dubbo(一)-SPI(2) 機制之 Dubbo 的 SPI
- Java SPI機制詳解Java
- SPI機制與策略模式模式
- Java SPI機制簡述Java
- Spring SPI 機制總結Spring
- ATL Thunk機制深入分析
- 理解的Java中SPI機制Java
- Dubbo 原始碼分析 - SPI 機制原始碼
- Skywalking-12:Skywalking SPI機制
- Java-SPI機制詳解Java
- Go 包管理機制深入分析Go
- Dubbo原始碼解析之SPI機制原始碼
- 深入理解 Java 中 SPI 機制Java
- springboot-starter中的SPI 機制Spring Boot
- 搞懂Dubbo SPI可擴充機制
- 深入剖析 Spring Boot 的 SPI 機制Spring Boot
- Java SPI機制總結系列之萬字最詳細圖解Java SPI機制原始碼分析Java圖解原始碼
- JDK原始碼解析之Java SPI機制JDK原始碼Java
- Dubbo(一)-SPI 機制之javaSPI基礎Java
- Java SPI機制,你瞭解過嗎?Java
- 【一文讀懂】SPI機制之JAVA的SPI實現詳解Java
- 淺析Dubbo的SPI擴充套件機制套件
- 由淺入深理解Dubbo的SPI機制
- 你應該瞭解的 Java SPI 機制Java
- 從Dubbo核心-SPI聊聊雙親委派機制
- Java SPI 機制,「可插拔」的奧義所在~Java
- 詳解Apache Dubbo的SPI實現機制Apache
- 深入分析Redis的主從複製機制Redis
- 對Koa-middleware實現機制的深入分析
- SPI機制剖析——基於DriverManager+ServiceLoader的原始碼分析原始碼
- Flutter 命令本質之 Flutter tools 機制原始碼深入分析Flutter原始碼
- SpringBoot應用篇之FactoryBean及代理實現SPI機制示例Spring BootBean
- Java SPI機制總結系列之開發入門例項Java
- Redis哨兵機制全面深入分析與講解[實戰演示篇]Redis