Dubbo Adaptive機制1 - 動態擴展加載、$Adaptive類

Dubbo的Adaptive機制是什么?

在回答這個問題之前,我們先說說擴展和Dubbo的SPI機制。

評價一個軟件擴展性好不好,說的是軟件本身有沒有預留足夠的擴展點,讓用戶去自定義軟件的功能,讓軟件調用你的代碼,運行你的代碼邏輯。比如在Web開發中,常常會自定義一些Filter,在一個請求的前后做一些額外的處理。用Java的語言來講,擴展點就是接口(Interface),擴展就是接口實現(implement)。

那Dubbo的SPI是什么?Dubbo的SPI機制,就是擴展點加載機制。Dubbo允許用戶在配置文件中配置擴展,形式為:key=value,key為擴展的名稱,value是擴展類的全限定名。例如,一個擴展點是Animal,有3個實現,分別是Dog、Cat、Tiger,在配置文件中做如下配置:
dog=com.xxx.Dog
然后在代碼中調用:
Animal dog = ExtensionLoader.getExtensionLoader(Animal.class).getExtension("dog");
即可獲取到Dog的實例。但是擴展名(dog)是寫死的,如果我想換成cat,需要寫成:
Animal cat = ExtensionLoader.getExtensionLoader(Animal.class).getExtension("cat");
寫死名稱很不靈活,在有些場景下,需要動態的獲取擴展,有時想要cat實例,有時需要dog實例。那怎么做呢,很簡單只要擴展名是一個變量,就可以實現動態獲取擴展了:
Animal animal = ExtensionLoader.getExtensionLoader(Animal.class).getExtension(animal);

Dubbo的Adaptive機制,正是利用URL這個參數,在運行過程中動態的加載擴展。具體為,@Adaptive注解定義從URL取哪個key,對應的value就是擴展的名稱:

URL url = arg.getUrl();
String extName = url.getParameter( "animal_type", "cat");
Animal extension = ExtensionLoader
                      .getExtensionLoader( Animal.class )
                      .getExtension( extName );

其中,animal_type是在注解@Adaptive中定義的,cat是默認的擴展名

Dubbo會為方法上標注有@Adaptive的擴展點,自動生成一個$Adaptive后綴的包裝類,包裝類中的邏輯,就是上述所說的從URL中獲取擴展名,再獲取擴展的過程。

最終,獲取adaptive擴展的代碼為:
Animal animal = ExtensionLoader.getExtensionLoader(Animal.class).getAdaptiveExtension();

下面具體看下Dubbo為我們生成的包裝類的代碼長什么樣?
以ProxyFactory為例,生成的ProxyFactory$Adaptive類的代碼如下:

@SPI("javassist")
public interface ProxyFactory {
    
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;
    
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;
    
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

}
public class ProxyFactory$Adaptive implements com.alibaba.dubbo.rpc.ProxyFactory {

    public java.lang.Object getProxy( com.alibaba.dubbo.rpc.Invoker arg0 ) throws com.alibaba.dubbo.rpc.RpcException
    {
        if ( arg0 == null )
            throw new IllegalArgumentException( "com.alibaba.dubbo.rpc.Invoker argument == null" );

        if ( arg0.getUrl() == null )
            throw new IllegalArgumentException( "com.alibaba.dubbo.rpc.Invoker argument getUrl() == null" );

        com.alibaba.dubbo.common.URL url    = arg0.getUrl();
        String extName = url.getParameter( "proxy", "javassist" );
        if ( extName == null )
            throw new IllegalStateException( "Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])" );

        com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader
                .getExtensionLoader( com.alibaba.dubbo.rpc.ProxyFactory.class )
                .getExtension( extName );

        return (extension.getProxy( arg0 ) );
    }

    // 省略其他2個方法
}

在這里打個斷點,就能看到動態拼接的adaptive包裝類的代碼:com.alibaba.dubbo.common.extension.ExtensionLoader#createAdaptiveExtensionClass

private Class<?> createAdaptiveExtensionClass() {
        String code = createAdaptiveExtensionClassCode();
        ClassLoader classLoader = findClassLoader();
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

下一篇,我們將從源碼的角度,分析Adaptive機制。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370