前面有說到 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
從這點來看,Dubbo SPI 從使用上與 JAVA SPI 並沒有很大差別。函數
主要區別在於:this
JDK 標準的 SPI 會一次性實例化擴展點全部實現,若是有擴展實現初始化很耗時,但若是沒用上也加載,會很浪費資源。
而 Dubbo SPI 能夠選擇性實例化某個擴展接口實現類。spa
下面來看下寫法上的差異,具體代碼以下:.net
註解中的 value 爲 步驟 1.3 中配置的" 接口實現類的名稱",好比@SPI("helloService")
, 至關於指定默認的擴展實現類爲 com.nimo.service.impl.HelloServiceImpl
// 差異一:Dubbo 須要 SPI 註解 @SPI public interface HelloService { void sayHello(String name); }
public class HelloServiceImpl implements HelloService { @Override public void sayHello(String name) { System.out.println("hello, " + name); } }
# 差異二:文件夾命名方式不一樣,以及文件內容格式不一樣 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 省略。。。。
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 容器,它們各司其職,具體的後面源碼篇會詳細說。
ExtensionLoader 在加載擴展點時,若是加載到的擴展點有拷貝構造函數,則斷定爲擴展點 Wrapper 類。
這個有點相似 AOP,看下具體代碼和效果就明白了。
// 實現擴展接口以及以下模板的構造方法 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"); } }
// 第二步,在原有增長部份內容,更改後以下: 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()