JAVA 拾遺 -- 關於 SPI 機制

原文:https://www.cnkirito.moe/spi/

一、實現一個自定義的SPI

1.項目結構

  • invoker是用來測試的主項目
  • interface是針對廠商和插件商定義的接口項目,只提供接口,不提供實現
  • good-printer,bad-printer分別是兩個廠商對interface的不同實現,所以他們會依賴於interface項目

主要實現的是,在不改變invoker代碼,只更改依賴的前提下,切換interface的實現廠商

2.interface模塊

com.spi.Printer

public interface Printer {
    void print();
}

interface只定義一個接口,不提供實現。規範的制定方一般都是比較牛叉的存在,這些接口通常位於java,javax前綴的包中,這裏的printer只是模擬的一個規範接口。

3.good-printer模塊
3.1 good-printer\pom.xml
<dependencies>
    <dependency>
        <groupId>com.lara</groupId>
        <artifactId>interface</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

規範的具體實現類必然要依賴規範接口

3.2 com.spi.GoodPrinter
public class GoodPrinter implements Printer {
    public void print() {
        System.out.println("you are good");
    }
}

作爲printer規範接口的實現一

3.3 在resource下添加services文件

每一個SPI接口都需要在自己項目的靜態資源目錄中聲明一個services文件,文件名爲實現規範接口的類名全路徑,此例中便是 com.spi.Printer,文件中的內同則爲實現類的全路徑,此例中便是com.spi.GoodPrinter.

這樣一個廠商的實現便完成了。

4.bad-printer模塊

和上述的good-printer的實現一樣

4.1 bad-printer\pom.xml
<dependencies>
    <dependency>
        <groupId>com.lara</groupId>
        <artifactId>interface</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>
4.2com.spi.BadPrinter
public class BadPrinter implements Printer {
    public void print() {
        System.out.println("you are bad");
    }
}
4.3在resource下添加services文件

5.invoker模塊

這裏的invoker便是我們自己的項目了。如果一開始我們想使用廠商bad-printer的Printer實現,是需要將其的依賴引入

<dependencies>
    <dependency>
        <groupId>com.lara</groupId>
        <artifactId>interface</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>com.lara</groupId>
        <artifactId>bad-printer</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>
5.1編寫調用主類
public class MainClass {
    public static void main(String[] args) {
        ServiceLoader<Printer> printLoaders = ServiceLoader.load(Printer.class);
        for (Printer printer : printLoaders){
            printer.print();
        }
    }
}

ServiceLoader是java.util提個的用於加載固定類路徑下文件的一個加載器,正式它加載了對應接口聲明的實現類。

5.2打印結果1

在後續的方案中,想替換廠商的Printer實現,只需要將依賴更換,調用主類無需變更代碼,符合開閉原則。

5.3打印結果2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章