dubbo源碼分析 之 服務本地暴露
dubbo 在服務暴露發生了哪些事,今天我們就來分析一下整個服務暴露中的本地暴露。本地暴露需要服務提供方與服務消費方在同一個 JVM。下面我們來寫一個本地暴露使用的例子:
1 DemoService.java
2DemoServiceImpl.java
3application.xml – Spring配置文件
4Provider.java – 調用本地暴露的服務
使用context.getBean("demoServiceDubbo", DemoService.class)
這種方式來獲取Bean還不如使用context.getBean("demoService", DemoService.class)
InvokerListener
與Filter
這兩個擴展點。可能這是與整個服務保持統一性吧。(大家如果有不同的觀點歡迎留言)。下面我們就從源碼的角度來分析一下 dubbo 的本地暴露吧。
如果大家看過dubbo官網的API配置(建議大家分析碼源的時候都使用API的形式調用,盡量少的引入第三方Jar包比如xml配置dubbo
),我們就可以知道。dubbo服務的暴露的起點是ServiceConfig#export
。下面我們就以這個方法以起點來分析它:export
這個方法就是dubbo服務暴露的入口,主要就是判斷這個服務是否暴露以及通過ScheduledThreadPoolExecutor
doExport
方法,在這個方法的前面就是做一些 check 操作,不是重點,就不一一分析了。我們主要看一下它的appendProperties方法
以及doExportUrls
這兩個方法。appendProperties()
方法主要是為當前對象通過setter 方法來添加屬性,它主要是通過以下方式來添加屬性:
-
從 System 中獲取屬性key值的優先通訊是:
dubbo.provider.
+ 當前類 Id + 當前屬性名稱 >dubbo.provider.
+ 當前屬性名稱 為 key 獲取值. -
首先從特定properties文件加載屬性:首先
System.getProperty("dubbo.properties.file")
dubbo.properties
加載。獲取屬性的 key 和上面從 System 裏面獲取的規則一樣。
然後我們就來分析一下doExportUrl
這個方法,因為 Dubbo 允許配置多協議,在不同服務上支持不同協議或者同一服務上同時支持多種協議。所以這裏需要循環各個協議進行多協議暴露服務。
然後我們來分析一下ServiceConfig#doExportUrlsFor1Protocol,首先我們來看一下appendParameters(Map, Object)這個方法,這個方法的作用就是通過調用當前對象的getter方法獲取到傳入對象的值然後塞到 map 當中去。用於後面的構造URL這個對象。
註:URL,配置信息的統一格式,所有擴展點都通過傳遞 URL 攜帶配置信息)
如果大家沒有看過我6、dubbo源碼分析 之 服務暴露概述在這點我再向大家提醒一下,dubbo的對象扭轉過程是:
服務配置類 –> Invoker –> Exporter
首先通過 ref (服務實現類)、服務接口類以及 URL 默認通過 javassist,也就是 JavassistProxyFactory類獲取到代理對象。
然後再把 Invoker 對象轉化成Exporter對象。還記得之前的5.dubbo源碼分析 之 SPI分析之前是分析的遠程暴露中的獲取Protocol 實例。只是這裏的 protocol實例是 本地方法暴露獲取的實例。它也是 dubbo 自定義的 SPI 生成的 Protocol$Adaptive通過它的getExtension(name)方法創建 Protocol實例,然後通過 Protocol#export 方法獲取Exporter。
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
進行服務暴露的時候:
因為 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 服務暴露的本地暴露的過程。
其實整個 dubbo 的本地暴露邏輯還是蠻簡單的,把它分開來主要還是整個服務暴露過程比較復雜。先給大家講解一下本地暴露。如果大家清楚了本地暴露,然後再理解遠程暴露就會更加容易。
dubbo源碼分析 之 服務本地暴露