Dubbo SPI 的使用方法(一)- 擴展點自動包裝

開篇

前面有說到 Java SPI 的介紹與使用方法, 而本篇要說的 Dubbo SPI 是基於 Java SPI 的一個升級與改造(改善了部分缺點,增長了幾個新玩法)。具體內容能夠去看官網 Dubbo-SPI 部分html

本文主要來說下 Dubbo SPI 的部分使用方法。java

另外,後續文章會補齊 Dubbo SPI 的其餘用法以及 Dubbo SPI 部分的源碼解析。apache

固然 官網 也有 Dubbo SPI 的使用說明與源碼導讀,能夠自行選擇。segmentfault

正文

Dubbo SPI 的使用方法具體分爲如下部分:app

  • 基本使用
  • 擴展點自動包裝
  • 擴展點自適應
  • 擴展點自動裝配
  • 擴展點自動激活

本文先來介紹前兩種使用方法,建議先看下 Java SPI 的介紹與使用方法,瞭解下 SPI 的機制及用途。ide

1. 基本使用

從這點來看,Dubbo SPI 從使用上與 JAVA SPI 並沒有很大差別。函數

主要區別在於:this

JDK 標準的 SPI 會一次性實例化擴展點全部實現,若是有擴展實現初始化很耗時,但若是沒用上也加載,會很浪費資源。

而 Dubbo SPI 能夠選擇性實例化某個擴展接口實現類。spa

下面來看下寫法上的差異,具體代碼以下:.net

1.1 定義一個接口

註解中的 value 爲 步驟 1.3 中配置的" 接口實現類的名稱",好比@SPI("helloService"), 至關於指定默認的擴展實現類爲
com.nimo.service.impl.HelloServiceImpl

// 差異一:Dubbo 須要 SPI 註解
@SPI
public interface HelloService {

    void sayHello(String name);

}

1.2 定義接口的實現類

public class HelloServiceImpl implements HelloService {
    @Override
    public void sayHello(String name) {
        System.out.println("hello, " + name);
    }
}

1.3 在 classpath 下建立以下文件

# 差異二:文件夾命名方式不一樣,以及文件內容格式不一樣
META-INF\dubbo\com.nimo.service.HelloService (以接口名全路徑命名)

文件內容爲:key-value 形式

helloService=com.nimo.service.impl.HelloServiceImpl
# 能夠有多個實現
helloService1=com.nimo.service.impl.HelloServiceImpl1
helloService2=com.nimo.service.impl.HelloServiceImpl2
省略。。。。

1.4 程序入口

public class App 
{
    public static void main( String[] args )
    {
        // 差異三: API 不一樣
        ExtensionLoader<HelloService> extensionLoader = ExtensionLoader.getExtensionLoader(HelloService.class);
        // 經過指定擴展類名稱y ,獲取對應實例化對象
        // 這裏 extensionLoader 能夠把它看成一個 map
        // 若是參數爲 」true「,會加載默認的擴展類
        HelloService helloService = extensionLoader.getExtension("helloService");
        helloService.sayHello("xiaoming");
    }
}

運行結果:

hello, xiaoming

其實 ExtensionLoader 內部確實有不少 ConcurrentHashMap 容器,它們各司其職,具體的後面源碼篇會詳細說。

2. 擴展點自動包裝

ExtensionLoader 在加載擴展點時,若是加載到的擴展點有拷貝構造函數,則斷定爲擴展點 Wrapper 類。

這個有點相似 AOP,看下具體代碼和效果就明白了。

2.1 新增一個類

// 實現擴展接口以及以下模板的構造方法
public class HelloServiceImplWrapper implements HelloService {

    private HelloService helloService;

    public HelloServiceImplWrapper(HelloService helloService){
        this.helloService = helloService;
    }

    @Override
    public void sayHello(String name) {
        // 這裏至關於對原有的 Service 進行了加強
        System.out.println("before");
        helloService.sayHello(name);
        System.out.println("after");
    }
}

2.2 修改 META-INFdubbocom.nimo.service.HelloService 文件內容

// 第二步,在原有增長部份內容,更改後以下:
helloService=com.nimo.service.impl.HelloServiceImpl
helloService=com.nimo.service.impl.HelloServiceImplWrapper

運行結果:

before
hello, xiaoming
after

總結

本文先引入 Dubbo SPI 的基本使用,而後介紹了其中一個高級玩法-擴展點自動包裝,
它的做用正如官網所說,相似一個 AOP。

另外,經過 ExtensionLoader 獲取擴展點的實現類的具體實例時,大體僞代碼以下所示:

HelloService helloService = new HelloServiceImpl();
if (wrapper 存在) {
   helloService = wrapper; 
}
return helloService;

最後調用 sayHello方法時,就是調用的 wrapper.sayHello()

相關文章
相關標籤/搜索