【dubbo】java SPI (Service Provider Interface)

看dobbo源碼的時候,有幾個類繞來繞去的,在調用Protocol的導出服務時,怎麼也沒找到在哪兒配置的具體實現,例如Exporter<?> exporter = protocol.export(invoker); 在debug調試時,看protocol的類型是
com.alibaba.dubbo.rpc.Protocol$Adpative,以下:html

經過命名能夠看出,這是屬於com.alibaba.dubbo.rpc.Protocol類的一個內部類,而這個內部類在Protocol類中又沒有定義,真正調用export方法時,調用的真正實現是RegistryProtocol。着實費解,而後去看Protocol這個接口,看到這個接口上有一個@SPI的註解,這個註解是dubbo框架本身定義的註解,忽然間想到Java的SPI,應該是dubbo本身實現了一套spi機制,因而去官方文檔去找了一下,確實有相關闡述。http://dubbo.io/developer-guide/%E6%89%A9%E5%B1%95%E7%82%B9%E5%8A%A0%E8%BD%BD.htmljava

咱們本身寫代碼的時候,這個東西用的比較少,可是在相關的框架中,仍是有一些應用的,例如commos-logging日誌包和新版的數據庫鏈接DriverManager,就用到Java SPI。程序員

SPI介紹

    爲了能夠實現可插拔的功能,也就是咱們經常使用的接口,上游廠商定義了標準,而具體的實現放在下游廠商中進行實現。各家下游廠商各自獨立實現不一樣的功能。很常見的就是咱們的電腦預留了USB的接口,USB接口就是一個標準,而後各家廠商生產本身的USB接口的鼠標,鍵盤等等其餘外設設備,它們須要符合USB接口的規範,具體的功能由各個生產廠家本身定製,用的時候插上,不用的時候拔掉,SPI(Service Provider Interface)就是基於這種思想的。
不會把硬代碼侵入到接口的定義中,而是把實現放在了外部。數據庫

約定

    基於這種思想,爲了方便廣大程序員使用,Java的jdk中實現了SPI機制,具體的類是Java.util.ServiceLoader,針對此機制,因此會有一些咱們使用上的約定,在這個類的文檔中,有對使用的約定的詳細描述,而且oracle文檔中也有闡述(http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html)總結以下:api

  1. 服務聲明者是一個接口或者是一個抽象類
  2.   在META-INF文件夾下須要有一個services文件夾
  3. services文件夾下有一個文件,名稱是服務提供者的全類名,而且文件的格式是UTF-8的
  4. 文件中只有一行,就是實現類的全稱(包名和類名)不能有空格以及其餘不可見的字符

示例

    實現一個打印機的功能,聲明一個打印機接口,接口中有一個打印方法doPrint,而後oracle

類結構以下:
├─java
│  └─com
│      └─tofuwang
│          └─myrpc
│              └─spi
│                      BlackPrinter.java
│                      Printer.java
│                      PrintMain.java
└─resources
    └─META-INF
        │services
                com.tofuwang.myrpc.spi.Printer
定義一個打印機接口Printer,裏面有一個打印的方法doPrint框架

public interface Printer {
    public void doPrint(String body);
}

有一個黑白打印機的類BlackPrinter,實現了Printer接口ide

public class BlackPrinter implements Printer {
    @Override
    public void doPrint(String body) {
        System.out.println("黑白打印機打印出內容:"+body);
    }
}

調用方式以下,在PrintMain中定義ui

public class PrintMain {
    public static void main(String[] args) {
        ServiceLoader<Printer> load = ServiceLoader.load(Printer.class);
        Iterator<Printer> iterator = load.iterator();
        while (iterator.hasNext()){
            Printer next = iterator.next();
            next.doPrint("社會主義好!");
        }
    }
}

在main方法中,並無對黑白打印的顯示調用,可是確實是有黑白打印機的輸出。spa

以上就是一個很是淺顯的SPI使用示例。

相關文章
相關標籤/搜索