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的擴充套件機制
- 簡單功能介紹
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分三種情況來分別儲存對應的實現者,屬性分別如下:
-
Class<?> cachedAdaptiveClass;//自適配物件
-
Set<Class<?>> cachedWrapperClasses;//包含介面類的構造方法,wrapper物件
-
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<?>>>();