參考:http://dubbo.apache.org/zh-cn/docs/source_code_guide/dubbo-spi.html
1.簡介
SPI 全稱爲 Service Provider Interface,是一種服務發現機制。SPI 的本質是將接口實現類的全限定名配置在文件中,並由服務加載器讀取配置文件,加載實現類。這樣可以在運行時,動態爲接口替換實現類。正因此特性,我們可以很容易的通過 SPI 機制爲我們的程序提供拓展功能。SPI 機制在第三方框架中也有所應用,比如 Dubbo 就是通過 SPI 機制加載所有的組件。不過,Dubbo 並未使用 Java 原生的 SPI 機制,而是對其進行了增強,使其能夠更好的滿足需求。在 Dubbo 中,SPI 是一個非常重要的模塊。基於 SPI,我們可以很容易的對 Dubbo 進行拓展。如果大家想要學習 Dubbo 的源碼,SPI 機制務必弄懂。接下來,我們先來了解一下 Java SPI 與 Dubbo SPI 的用法,然後再來分析 Dubbo SPI 的源碼。
需要特別說明的是,本篇文章的源碼版本爲 dubbo-4.0.0。因此大家在閱讀文章的過程中,需注意將代碼版本切換到 dubbo-4.0.0 tag 上。
dubbo的目錄結構如下,感興趣的可以自行到github上去下載到本地
本次記錄的ExtensionLoader用法是在如下目錄下。
首先咱們 先來看一下他的基本用法
找到dubbo的test
我們來隨便在測試類裏面寫個測試
@Test public void testExt2() throws Exception { ExtensionLoader<Ext2> extensionLoader = ExtensionLoader.getExtensionLoader(Ext2.class); Ext2 impl1 = extensionLoader.getExtension("impl1"); String value = impl1.echo(new UrlHolder(), "2"); System.err.println(value); //========================== Ext2 impl2 = extensionLoader.getExtension("impl2"); String value2 = impl2.echo(new UrlHolder(), "2"); System.err.println(value2); }
點擊Ext2類進去看見是一個接口
@SPI public interface Ext2 { // one of the properties of an argument is an instance of URL. @Adaptive String echo(UrlHolder holder, String s); String bang(URL url, int i); }
並且是加了@SPI和在方法上加了 @Adaptive註解的接口,這裏需要留意下。後面源碼分析時候會講到。
通過idea看見Ext2 有定義了三個實現類
三個實現類幾乎一樣,只是作爲區分而已
public class Ext2Impl2 implements Ext2 { public String echo(UrlHolder holder, String s) { return "Ext2Impl2-echo"; } public String bang(URL url, int i) { return "bang2"; } }
接下來看一下三個實現類定義的文件
內容爲:
impl1=org.apache.dubbo.common.extension.ext2.impl.Ext2Impl1 impl2=org.apache.dubbo.common.extension.ext2.impl.Ext2Impl2 impl3=org.apache.dubbo.common.extension.ext2.impl.Ext2Impl3
可以看出是個鍵值對。值爲實現類的全類名。
運行測試類得到如下
Dubbo SPI 除了支持按需加載接口實現類,還增加了 IOC 和 AOP 等特性。
上面簡單演示了 Dubbo SPI 的使用方法。我們首先通過 ExtensionLoader 的 getExtensionLoader 方法獲取一個 ExtensionLoader 實例,然後再通過 ExtensionLoader 的 getExtension 方法獲取拓展類對象。這其中,getExtensionLoader 方法用於從緩存中獲取與拓展類對應的 ExtensionLoader,若緩存未命中,則創建一個新的實例。該方法的邏輯比較簡單,本章就不進行分析了。下面我們從 ExtensionLoader 的 getExtension 方法作爲入口,對拓展類對象的獲取過程進行詳細的分析。
由於篇幅有限並且文章太長會讓讀者沒興趣看下去。下篇我們再來看Dubbo 的SPI 源碼。