Dubbo SPI,ExtensionLoader之getExtension和getAdaptiveExtension的區別與聯繫

在dubbo中,大量的使用了ExtensionLoader進行接口實現類的擴展,也就是SPI機制,ExtensionLoader會掃描classpath下與擴展接口全路徑名一致的配置文件,如下

 

文件中配置的都是擴展接口的實現類,調用ExtensionLoader的get類方法後,其會讀取上述文件中所有的key=value鍵值對,加載value對應的class,並緩存到本地map中,key對應配置文件中的key,value對應Class對象。

ExtensionLoader提供了兩類get方法,getExtension(key)和getAdaptiveExtension()

1.getExtension(key)方法很好理解,從本地map中找到對應key的class對象,通過反射創建該class對象的實例對象並返回

2.getAdaptiveExtension()方法複雜一些,會通過字符串拼接出一個java文件文本,然後通過動態編譯以及類加載,將該類文件對應的class載入到內存,該類是一個實現了擴展接口的java類,部分內容如下:

可以看到,類名後面是個Adaptive,再結合方法名getAdaptiveExtension以及下面的方法說明,我們可以知道,生成的類是一個適配器類,完成的僅僅是適配功能,我下面截取生成類文件中的一個方法來作說明:

方法中除了做了一些基本校驗外,主要就是一個轉發,關鍵代碼已用紅框標出,

1).首先獲取url,url是在容器啓動時從我們配置的<dubbo:reference>或者<dubbo:service>中解析出來的,我隨便舉個消費者訂閱url的例子方便大家理解:consumer://172.31.30.25/org.apache.dubbo.demo.DemoService?application=demo-consumer&check=false&dubbo=2.0.2&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=37740&qos.port=33333&side=consumer&timeout=60000&timestamp=1554189149262可以看到url中包含了許多參數,我這裏列舉的遠遠不是全部,很多參數都是可選的,不指定的話dubbo就會給一個默認值),

2).然後對extName取值,再通過上面介紹的getExtension(key)方法獲取最終實現類,並調用其對應方法

String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());

這行代碼裏的”dubbo“表示默認key,哪裏來的呢?

在dubbo中,每個可擴展的接口上,都有@SPI註解,其中()內的屬性值就是獲取實現類的默認key,代表該接口的默認實現類,例如上述的Protocol接口的默認實現類爲DubboProtocol

        getAdaptiveExtension()方法的好處在於,可以根據用戶配置的<dubbo:reference>或者<dubbo:service>來動態決定實際運行中,使用的是哪種實現類。

        並且,我們也可以根據這個特性來自定義我們的實現類,並按照文件的配置規則進行配置,比如自定義一個Protocol實現類叫com.bowang.dubbo.MyPrototcol implements ,在我們的項目src/main/resources/META-INF/internal下創建一個org.apache.dubbo.rpc.Protocol文件,內容如下

                      myProtocol=com.bowang.dubbo.MyPrototcol

然後在<dubbo:reference>中指定protocol="myProtocol",如此,就可以實現自定義擴展Protocol了

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章