1. 程式人生 > >Java SPI + Dubbo SPI

Java SPI + Dubbo SPI

SPI-Service Provider Interface : 服務提供介面

Java SPI + Dubbo SPI

Java SPI + Dubbo SPI 的區別

Java SPI

1.簡單的總結下java spi機制的思想

我們系統裡抽象的各個模組,往往有很多不同的實現方案,比如日誌模組的方案,xml解析模組、jdbc模組的方案等。
java spi就是提供這樣的一個機制:為某個介面尋找服務實現的機制。有點類似IOC的思想,就是將裝配的控制權移到程式之外,在模組化設計中這個機制尤其重要

2.SPI具體約定

java spi的具體約定為:當服務的提供者,提供了服務介面的一種實現之後,在jar包的META-INF/services/目錄裡同時建立一個以服務介面命名的檔案。
該檔案裡就是實現該服務介面的具體實現類。而當外部程式裝配這個模組的時候,就能通過該jar包META-INF/services/裡的配置檔案找到具體的實現類名,
並裝載例項化,完成模組的注入。 基於這樣一個約定就能很好的找到服務介面的實現類,而不需要再程式碼裡制定。
jdk提供服務實現查詢的一個工具類:java.util.ServiceLoader

3.缺點

雖然ServiceLoader也算是使用的延遲載入,但是基本只能通過遍歷全部獲取,也就是介面的實現類全部載入並例項化一遍。如果你並不想用某些實現類,它也被載入並例項化了,這就造成了浪費。獲取某個實現類的方式不夠靈活,只能通過Iterator形式獲取,不能根據某個引數來獲取對應的實現類

Dubbo SPI

具體還是要看下dubbo原始碼,這個是我看過原始碼之後理的邏輯圖:

在這裡插入圖片描述

dubbo的擴充套件機制

  1. 簡單功能介紹

dubbo的擴充套件機制和java的SPI機制非常相似,但是又增加了如下功能:
1 可以方便的獲取某一個想要的擴充套件實現,java的SPI機制就沒有提供這樣的功能
2 對於擴充套件實現IOC依賴注入功能:
舉例來說:介面A,實現者A1、A2。介面B,實現者B1、B2。
現在實現者A1含有setB()方法,會自動注入一個介面B的實現者,此時注入B1還是B2呢?都不是,而是注入一個動態生成的介面B的實現者B$Adpative,該實現者能夠根據引數的不同,自動引用B1或者B2來完成相應的功能
3 對擴展采用裝飾器模式進行功能增強,類似AOP實現的功能
還是以上面的例子,介面A的另一個實現者AWrapper1。大體內容如下:
private A a;
AWrapper1(A a){
this.a=a;
}
因此,我們在獲取某一個介面A的實現者A1的時候,已經自動被AWrapper1包裝了。

2 . dubbo的ExtensionLoader解析擴充套件過程

對於一個介面的實現者,ExtensionLoader分三種情況來分別儲存對應的實現者,屬性分別如下:

  1. Class<?> cachedAdaptiveClass;//自適配物件

  2. Set<Class<?>> cachedWrapperClasses;//包含介面類的構造方法,wrapper物件

  3. Holder<Map<String, Class<?>>> cachedClasses;//

    情況1: 如果這個class含有@Adaptive註解,則將這個class設定為Class<?> cachedAdaptiveClass。

      /**
      * 快取的自適應拓展物件的類
      *
      * {@link #getAdaptiveExtensionClass()}
      */
     private volatile Class<?> cachedAdaptiveClass = null;
    

    情況2: 如果類實現沒有打上@Adaptive,嘗試獲取帶對應介面引數的構造器,如果能夠獲取到,則說明這個class是一個裝飾類即,需要存到Set<Class<?>> cachedWrapperClasses中

     /**
      * 拓展 Wrapper 實現類集合
      *
      * 帶唯一引數為拓展介面的構造方法的實現類
      *
      * 通過 {@link #loadExtensionClasses} 載入
      */
     private Set<Class<?>> cachedWrapperClasses;
    

    情況3: 如果沒有上述構造器。則獲取class上的Extension註解,根據該註解的定義的name作為key,存至Holder<Map<String, Class<?>>> cachedClasses結構中

     /**
      * 快取的拓展實現類集合。
      *
      * 不包含如下兩種型別:
      *  1. 自適應拓展實現類。例如 AdaptiveExtensionFactory
      *  2. 帶唯一引數為拓展介面的構造方法的實現類,或者說拓展 Wrapper 實現類。例如,ProtocolFilterWrapper 。
      *     拓展 Wrapper 實現類,會新增到 {@link #cachedWrapperClasses} 中
      *
      * 通過 {@link #loadExtensionClasses} 載入
      */
     private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();