dubbo源碼分析 之 服務本地暴露

 dubbo 在服務暴露發生了哪些事,今天咱們就來分析一下整個服務暴露中的本地暴露。本地暴露須要服務提供方與服務消費方在同一個 JVM。下面咱們來寫一個本地暴露使用的例子:html

1 DemoService.javajava

1.png

2DemoServiceImpl.javaapi

1.png

3application.xml – Spring配置文件app

1.png

4Provider.java – 調用本地暴露的服務jvm

1.png

使用context.getBean("demoServiceDubbo", DemoService.class)這種方式來獲取Bean還不如使用context.getBean("demoService", DemoService.class)來獲取真正對象。前一種方式獲取到是 dubbo 返回的代理類,其中能夠獲取到 dubbo 的InvokerListenerFilter這兩個擴展點。可能這是與整個服務保持統一性吧。(你們若是有不一樣的觀點歡迎留言)。下面咱們就從源碼的角度來分析一下 dubbo 的本地暴露吧。ide

若是你們看過dubbo官網的API配置(建議你們分析碼源的時候都使用API的形式調用,儘可能少的引入第三方Jar包好比xml配置dubbo),咱們就能夠知道。dubbo服務的暴露的起點是ServiceConfig#export。下面咱們就以這個方法以起點來分析它:2.pngexport這個方法就是dubbo服務暴露的入口,主要就是判斷這個服務是否暴露以及經過ScheduledThreadPoolExecutor這個線程池類支持延遲暴露。1.png接下來就是doExport方法,在這個方法的前面就是作一些 check 操做,不是重點,就不一一分析了。咱們主要看一下它的appendProperties方法以及doExportUrls這兩個方法。appendProperties()方法主要是爲當前對象經過setter 方法來添加屬性,它主要是經過如下方式來添加屬性:源碼分析

  • 從 System 中獲取屬性key值的優先通信是: dubbo.provider. + 當前類 Id + 當前屬性名稱 > dubbo.provider. + 當前屬性名稱 爲 key 獲取值.spa

  • 首先從特定properties文件加載屬性:首先 System.getProperty("dubbo.properties.file")獲取到文件路徑,若是獲取不到就會試圖加載 dubbo 的默認的路徑 dubbo.properties加載。獲取屬性的 key 和上面從 System 裏面獲取的規則同樣。線程

而後咱們就來分析一下doExportUrl這個方法,由於 Dubbo 容許配置多協議,在不一樣服務上支持不一樣協議或者同一服務上同時支持多種協議。因此這裏須要循環各個協議進行多協議暴露服務。3d

1.png

而後咱們來分析一下ServiceConfig#doExportUrlsFor1Protocol,首先咱們來看一下appendParameters(Map, Object)這個方法,這個方法的做用就是經過調用當前對象的getter方法獲取到傳入對象的值而後塞到 map 當中去。用於後面的構造URL這個對象。

1.png

注:URL,配置信息的統一格式,全部擴展點都經過傳遞 URL 攜帶配置信息)

 

1.png

 

若是你們沒有看過我六、dubbo源碼分析 之 服務暴露概述在這點我再向你們提醒一下,dubbo的對象扭轉過程是:

服務配置類 –> Invoker –> Exporter

首先經過 ref (服務實現類)、服務接口類以及 URL 默認經過 javassist,也就是 JavassistProxyFactory類獲取到代理對象。

1.png

而後再把 Invoker 對象轉化成Exporter對象。還記得以前的5.dubbo源碼分析 之 SPI分析以前是分析的遠程暴露中的獲取Protocol 實例。只是這裏的 protocol實例是 本地方法暴露獲取的實例。它也是 dubbo 自定義的 SPI 生成的 Protocol$Adaptive經過它的getExtension(name)方法建立 Protocol實例,而後經過 Protocol#export 方法獲取Exporter。

1.png

1.png

dubbo 的定義 SPI 裏面包括 AOP,其實就是獲取到全部的 SPI 接口的實例對象。而後在調用 getExtension(name)方法返回指定名字的擴展的時候會判斷哪些實現類的構造器只包含 SPI 接口就會進行代理。這裏的name是從 URL 中獲取協議。在調用ServiceConfig#loadRegistries方法的裏面返回的 URL 格式爲registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?xxx=xxx而後再調用ServiceConfig#exportLocal(URL)方法的時候裏面把協議(protocol)設置成injvm, 而後 在 Protocol$Adaptive 進行服務暴露的時候:

1.png

 

由於 duubo 默認在dubbo-rpc-injvm的自定義Protocol配置文件(${dubbo-rpc-injvm}/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol)配置的是injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol因此獲得的對象是InjvmProtocol。由於ProtocolListenerWrapper 與 ProtocolFilterWrapper 其實都包括 SPI 接口 Protocol的構造器。因此建立出來的對象如上因此。關於 dubbo 的SPI機制能夠參看 – 2.dubbo源碼分析 之 內核SPI實現.

 

ProtocolListenerWrapper : 經過 SPI 機制獲取到 dubbo 的自定義擴展 InvokerListener。

ProtocolFilterWrapper : 經過 SPI 機制獲取到 dubbo 的自定義擴展 Filter(經常使用)。

其實關於 dubbo 經過 SPI 機制獲取機制獲取到 dubbo 的自定義擴展 Filter,還蠻複雜與重要的。在這裏就很少說了,感興趣的朋友能夠下去參看源碼。

 

最終就到了InjvmProtocol暴露服務,其實它就是建立一個 InjvmExporter 對象返回。裏面包括 4 個屬性:

 

invoker:Invoker 對象實例

key:服務 key 值,在進行服務調用的時候會根據這個 key 值。獲取到當前服務暴露生成的 Exporter 對象。

exporterMap:服務 key 值與當前 Exporter 的映射

最後這個生成的 Exporter 最終會返回添加到 ServiceConfig的 exporters 屬性當中去。這樣就完成了 dubbo 服務暴露的本地暴露的過程。

1.png

其實整個 dubbo 的本地暴露邏輯仍是蠻簡單的,把它分開來主要仍是整個服務暴露過程比較複雜。先給你們講解一下本地暴露。若是你們清楚了本地暴露,而後再理解遠程暴露就會更加容易。

 

相關文章
相關標籤/搜索