dubbo擴展點

  一.目的:

   使用者能夠不改dubbo項目的情況下,在應用項目中增加相應類及配置就可以實現擴展。


  二.類似jdk的spi,但比jdk spi有以下優勢:

  1.jdk的spi默認會加載並實例化所有擴展點類,如果對應擴展點沒用到且實例化消耗大,則是個耗資源的點。

  2.不支持依賴注入,即如果在擴展點類a中,有b擴展點屬性實例,則在加載擴展點類a時不會自動注入b。

  3.加載擴展點失敗會吞掉異常,比如加載一個擴展類a,如果其所依賴的jar找不到,不會報這個錯誤,反而會報不支持。


  三.實現原理:

  有個核心的ExtensiontLoader用於加載擴展點。

  dubbo規定,protocal, filter, transport等都存在獨立的ExtensionLoader。

  注入使用的時候,對應擴展點類是織入相應字節碼的類,主要是爲了實現運行時動態根據調用的url相應參數去查找具體的擴展點實現類。

  protocal實現類:

   會生成以下類:

 

class Protocol$Adpative implements Protocol{
    public com.alibaba.dubbo.rpc.Exporter export(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.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) {
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); 
        }
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)com.alibaba.dubbo.common.ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }

    public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0,com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException{
        if (arg1 == null)  { 
            throw new IllegalArgumentException("url == null"); 
        }
        com.alibaba.dubbo.common.URL url = arg1;
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) {
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); 
        }
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)com.alibaba.dubbo.common.ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }

    public void destroy(){
        throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }
}

  這裏可以看到,主要是實現了根據url的protocal屬性去查找對應的擴展點實現類。

  默認實現類優先取Adaptive標註上對應key的擴展點類。取不到則取spi標註上對應類。

  

  四.使用示例:

  增加一個dubbo方法執行時間log。

  這裏通過增加一個filter來解決,dubbo提供了fiter擴展點。

  需要進行以下步驟:

  1.創建filter類

    這裏是:XxxFilter


  2.建立以下目錄及文件

   這裏的META-INF, dubbo及 com.alibaba.dubbo.rpc.Filter文件,裏面有對應內容:

     

xxx=com.xxx.XxxFilter

注:這裏的xxx在用到的地方引用即可。比如在服務提供方上加入: <dubbo:provider filter="xxx"/>
然後擴展點加載類就會加載【com.alibaba.xxx.XxxFilter

    

·

    

 3.在使用的地方引用上述的【xxx】

   

在服務提供方上加入: <dubbo:provider filter="xxx"/>,這裏的xxx是對應擴展點目錄文件內容中對應key值。
然後擴展點加載類就會加載【com.alibaba.xxx.XxxFilter

  

 五.dubbo filter原理 

   dubbo在暴露服務時,會對invoker做一層封裝,使得filter能夠正常執行。

   比如存在:a,b,c三個filter,要執行的inovker是target。

   則會形成鏈表:a->b->c->target

  最終這個target對應服務被調用時,會依次執行a,b,c,target。

  



發佈了142 篇原創文章 · 獲贊 8 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章