1. 程式人生 > >5.dubbo原始碼分析 之 SPI分析

5.dubbo原始碼分析 之 SPI分析

如果大家看過之前的 dubbo 核心 SPI 實現 – 2.dubbo原始碼分析 之 核心SPI實現, 有可能還是一頭霧水,下面我講一下dubbo的具體應用。最典型的應用就是 Protocol 介面。

Protocol 屬於 dubbo 十層結構 中的遠端呼叫層, 它封裝了RPC呼叫。以Invocation 和 Result 為中心, 其它的擴充套件介面還包括 Invoker 和 Exporter。 Protocol 是服務域, 它是 Invoker 暴露和引用的主功能入口, 它負責 Invoker 的生命週期管理。
Invoker是實體域, 它是Dubbo的核心模型, 其它模型都向它靠擾, 或轉換成它. 它代表一個可執行體,可向它發起invoke呼叫,它有可能是一個本地的實現,也可能是一個遠端的實現,也可能一個叢集實現。

PS: 大家可以把 dubbo 的日誌級別設定為 debug 級別。這樣 dubbo 由 Javassist 位元組碼框架生成代理物件就會列印到控制檯。大家可以把建立這個類, 然後就可以 debug 這個類了。

在服務端配置類中 ServiceConfig 中我們可以看到它聚合了 Protocol。 而且是通過 dubbo 自己實現的 SPI 機制獲取的。當我們啟動 dubbo 原始碼中的 dubbo-demo 中的 com.alibaba.dubbo.demo.provider.Provider 類的時候就會進行服務釋出。我們可以在控制檯中看到生成的 Protocol 介面的動態代理類 Protocol$Adaptive:

這裡寫圖片描述

我們只需要把這個類按生成的規則, 也就是包名與類名一致的放在 dubbo 原始碼中就可以 debug 這個類了。

這裡寫圖片描述

在之前講 dubbo 的 SPI 機制中, 我們知道 dubbo 在通過 ExtensionLoader#createExtension 方法來建立相應的 SPI 的擴充套件。在這個方法中 dubbo SPI 實現了自己的 IOC 與 AOP。

private T createExtension(String name) {
    // 獲取解析Adaptive標註了@Adaptive的物件快取在屬性cachedNames
    Class<?> clazz = getExtensionClasses().get
(name); if (clazz == null) { throw findException(name); } try { // 從已建立Extension例項快取中獲取 T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } // dubbo ioc injectExtension(instance); Set<Class<?>> wrapperClasses = cachedWrapperClasses; // dubbo aop if (wrapperClasses != null && wrapperClasses.size() > 0) { for (Class<?> wrapperClass : wrapperClasses) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } return instance; } catch (Throwable t) { throw new IllegalStateException("Extension instance(name: " + name + ", class: " + type + ") could not be instantiated: " + t.getMessage(), t); } }

injectExtension 方法中是 dubbo 實現自己的依賴注入。 dubbo 通過 ExtensionFactory 來獲取需要依賴注入的物件。然後對當前例項通過反射呼叫 setter 方法來進行依賴注入。

當dubbo進行服務暴露的時候。首先是通過 Protocol 的 SPI 介面 與 獲取到 RegistryProtocol 例項。然後通過 dubbo 的 aop把這個物件先代理到 ProtocolListenerWrapper, 然後再將代理後的物件代理到 ProtocolFilterWrapper中。

1、呼叫SPI生成的代理物件

呼叫SPI生成的代理物件, 物件 dubbo 的SPI 機制通過 ExtensionLoader#createExtension 獲取到 RegistryProtocol例項。

這裡寫圖片描述

2、呼叫SPI的AOP生成最終物件

獲取到需要代理的物件,這裡的 cachedWrapperClasses 包裝物件是在解析 dubbo SPI 擴充套件檔案生成的。 這個物件的滿足的條件是實現了 SPI 介面, 並且有隻有 SPI 介面為構造器, 且配置在 SPI 擴充套件檔案的物件。我們可以看到針對 Protocol 介面,以下2個類滿足條件:

  • ProtocolListenerWrapper
  • ProtocolFilterWrapper

這裡寫圖片描述

它的執行過程如下:

  1. 通過dubbo的SPI獲取 RegistryProtocol 例項。
  2. 然後通過呼叫ProtocolListenerWrapper的 ProtocolListenerWrapper(Protocol protocol)生成代理物件, 然後再將代理後的物件傳入到ProtocolFilterWrapper的ProtocolFilterWrapper(Protocol protocol)中生成代理物件。
  3. 生成的最終物件返回到我們最開始說的ServiceConfig這個類中。