Java SPI(服務發現機制)


SPI 全稱為Service Provider Interface,是一種服務發現機制。SPI 的本質是將接口實現類的全限定名配置在文件中,並由服務加載器讀取配置文件,加載實現類。

這樣可以在運行時,動態為接口替換實現類。正因此特性,我們可以很容易的通過 SPI 機制為我們的程序提供拓展功能。

當服務的提供者提供了一種接口的實現之后,需要在 Classpath 下的 META-INF/services/ 目錄里創建一個以服務接口命名的文件,此文件記錄了該 jar 包提供的服務接口的具體實現類。當某個應用引入了該 jar 包且需要使用該服務時,JDK SPI 機制就可以通過查找這個 jar 包的 META-INF/services/ 中的配置文件來獲得具體的實現類名,進行實現類的加載和實例化,最終使用該實現類完成業務功能。

簡單點說SPI就是 JDK 內置的一個服務發現機制,它使得接口和具體實現完全解耦。我們只聲明接口,具體的實現類在配置中選擇。

具體的就是你定義了一個接口,然后在META-INF/services目錄下放置一個與接口同名的文本文件,文件的內容為接口的實現類,多個實現類用換行符分隔。

這樣就通過配置來決定具體用哪個實現!

例如,使用 Java 語言訪問數據庫時我們會使用到 java.sql.Driver 接口,不同數據庫產品底層的協議不同,提供的 java.sql.Driver 實現也不同,在開發 java.sql.Driver 接口時,開發人員並不清楚用戶最終會使用哪個數據庫,在這種情況下就可以使用 Java SPI 機制在實際運行過程中,為 java.sql.Driver 接口尋找具體的實現。

下面我們通過一個簡單的示例演示下 JDK SPI 的基本使用方式:

首先我們需要創建一個 Log 接口,來模擬日志打印的功能:

public interface Log { 
    void log(String info); 
} 

接下來提供兩個實現—— Logback 和 Log4j,分別代表兩個不同日志框架的實現,如下所示:

public class Logback implements Log { 
    @Override 
    public void log(String info) { 
        System.out.println("Logback:" + info); 
    } 
} 
public class Log4j implements Log { 
    @Override 
    public void log(String info) { 
        System.out.println("Log4j:" + info); 
    } 
} 

在項目的 resources/META-INF/services 目錄下添加一個名為 com.xxx.Log 的文件,這是 JDK SPI 需要讀取的配置文件,具體內容如下:

com.xxx.impl.Log4j 
com.xxx.impl.Logback 

最后創建 main() 方法,其中會加載上述配置文件,創建全部 Log 接口實現的實例,並執行其 log() 方法,如下所示:

public class Main { 
    public static void main(String[] args) { 
        ServiceLoader<Log> serviceLoader =  
                ServiceLoader.load(Log.class); 
        Iterator<Log> iterator = serviceLoader.iterator(); 
        while (iterator.hasNext()) { 
            Log log = iterator.next(); 
            log.log("JDK SPI");  
        } 
     // JDK8 Lamda表達式的forEach遍歷寫法
// serviceLoader.forEach(log -> log.log("hello")); } }
// 輸出如下: // Log4j:JDK SPI // Logback:JDK SPI

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM