Dubbo原始碼解析 —— 服務暴露原理
前言
之前講完了dubbo叢集容錯系列,現在開始講比較重要的環節,也就是dubbo面試中比較喜歡問的兩個點: 服務釋出
和 服務引用
.
插播面試題
- 服務釋出過程中做了哪些事
- dubbo都有哪些協議,他們之間有什麼特點,預設值是什麼
- 什麼是本地暴露和遠端暴露,他們的區別
直入主題
從啟動日誌說起
大家都知道, dubbo
是阿里巴巴開源的一個專案,前陣子阿里不僅釋出的程式碼規範手冊,還發布了相應的外掛,從這點我們就知道,阿里是很注重這個程式碼規範的,從 dubbo
專案我們也發現了,他有完善的測試體系.說了這麼說,那和我們今天要講的 dubbo的服務釋出
有什麼關係呢?當然有,一個規範的專案,必然是有健全的日誌系統.做過其他開發比如iOS開發的都知道,這個控制檯輸出在生產環境是不能隨便輸出的,太多日誌有時候和沒有日誌是一樣的.所以我們來看看這個服務啟動過程中,日誌究竟輸出了什麼.
這裡我用不同顏色的框將關鍵的地方畫了出來,一共有6種顏色,我一次從上到下說一下這釋出過程的一些動作
- 暴露本地服務
- 暴露遠端服務
- 啟動netty
- 連線zookeeper
- 到zookeeper註冊
- 監聽zookeeper
從文件入手,瞭解全域性
經常有人問到,看原始碼要怎麼看.要了解這個服務釋出,文件就是一個很好的切入口,如下
再獻上文件提供的一個時序圖
當然這些都是給已經對原始碼有一定熟悉的人看的,而我的原始碼解析類文件,是給對原始碼不熟悉的人看的.
其實我的每週一更dubbo原始碼系列文章,我的初衷有以下兩個,一個就是做到系統分享,比如dubbo系列文章,我會從不少於 核心
, 服務釋出
, 服務引用
編解碼
這四個模組去剖析,後面如果有時間,會臨摹一個簡易的dubbo框架.另一個初衷就是把自己思考的過程和大家分享,在這個分享過程中,其實就是回答了"怎麼看原始碼"這個問題
那麼準備好五菱巨集光,向秋名山出發
出發秋名山
我早年做Android開發的時候,就發現身邊的人都是死在了一個點上,那就是 配置環境
.對於看原始碼,很多人最常問的一句話就是,怎麼入手,也就是切入點.那麼我們還是以開頭的日誌為例,來找一個這個切入點
仔細看輸出日誌,就會發現在暴露本地服務之前,有一句很重要的日誌,就是
The service ready on spring started. service: com.alibaba.dubbo.demo.DemoService, dubbo version: <span class="hljs-number">2.0</span>.0, current host: <span class="hljs-number">127.0</span>.0.1
我們利用編譯器的搜尋文字功能,定位到了 ServiceBean
這個類,這個類是幹嘛的?好,我假設我也不知道,既然不知道,那我們來看一下他的繼承體系圖
從這個圖我們看到了許多和spring有關的東西,還發現了一個重要的介面,那就是 ApplicationListener
.要能敏銳的發現這個關鍵的介面,首先還是要對spring有一定了解,這個就是spring的事件機制(event).什麼是事件機制呢?就比如監聽 spring容器初始化完成
.那我們就定位到這行日誌的位置,往下debug
下面要開始敲黑板劃重點了.
從方法名我們很直觀知道目的,但是這裡同事不止一次問過我,這個 dubbo.properties
檔案是怎麼時候載入的,好像我根本沒有設定,另外這個 dubbo.properties
檔案的名字能不能改?面對這種問題,我從來都是不會直接把答案告訴他,而是告訴他,我是怎麼得到這個答案的,如下圖
同理,對於 log4j.xml
這個檔案,好像我從來沒有寫程式碼載入過,為什麼他會載入呢,其實也是同理的
接下來繼續往下走,下面這裡就是我們的第二道面試題
這裡為什麼會進行遍歷呢,因為dubbo是支援多協議的,看文件原話
dubbo支援多種協議,預設使用的是 dubbo
協議,具體介紹官方文件寫得很清楚,傳送地址:相關協議介紹
馬不停蹄,下面就到了第三個面試題,也是服務釋出的重點, 本地暴露
和 遠端暴露
為什麼會有 本地暴露
和 遠端暴露
呢?不從場景考慮討論技術的沒有意義是.在dubbo中我們一個服務可能既是 Provider
,又是 Consumer
,因此就存在他自己呼叫自己服務的情況,如果再通過網路去訪問,那自然是捨近求遠,因此他是有 本地暴露
服務的這個設計.從這裡我們就知道這個兩者的區別
- 本地暴露是暴露在JVM中,不需要網路通訊.
- 遠端暴露是將ip,埠等資訊暴露給遠端客戶端,呼叫時需要網路通訊.
本篇著重講解 服務釋出
的整體過程,細節和總結後面會陸續展開.我們忘記下.其實注意一下我這些截圖就能發現,我截的時候會特意把類名和方法名都截出來,方便大家能迅速定位.
從上圖可知,這裡用到了 Adaptive
(這個東西非常關鍵,後面會專門一篇講解).點進 ProxyFactory
檢視原始碼
@Adaptive
註解打在類上和方法上,他們是有區別的(面試也喜歡問這種區別類的問題,這個留在 Adaptive
專題說,記得關注肥朝每週一篇原始碼解析 _ ),他打在方法上,就會生成動態編譯的Adaptive類,下面就介紹一下怎麼看這個動態編譯類的原始碼
首先要將這個log4j的level調整為 DEBUG
為什麼需要調整成 DEBUG
,更重要的是把如何知道的,告訴大家,比如如下圖,當然這個時候可能會朋友說,我也不知道這個類也還是沒辦法找到這行程式碼.其實這個也是在後面專門的一篇 Adaptive
中會說,到時候我會提供另一種實現思路,我們一起思考對比優劣.
開啟 DEBUG
後,我們重新啟動,就會看到日誌有如下輸出,這段就是相關程式碼,我們根據包名新建檔案,如下
我們在 getInvoker
方法上打上斷點,重啟一下.
由上圖知道,本地暴露的url是以 injvm
開頭的,下面來看下遠端暴露,其實這個也是回答 本地暴露
和 遠端暴露
區別的一個回答點.面試回答要的並不是一個滿分的答案,而是從一些細節中,看出一個人,是否真的研究過原始碼.
還是回到開頭那句話, dubbo
命名是很規範的,從 Wrapper
這個命名,其實可以和Spring的 BeanWrapper
,以及裝飾者設計模式聯絡起來.同時可以看看文件中的
編碼約定
寫在最後
上面講到了 getInvoker
方法,也就是拿到了 Invoker
,如果注意到本篇開頭的文件說明中的那句 Dubbo處理服務暴露的關鍵就在Invoker轉換到Exporter的過程
,就知道,其實這個 服務暴露
還有很多細節是未完待續的,但是由於本篇已有一定篇幅,所以只能下週再見.
如果對你有所幫助,希望點贊,關注支援.鑑於本人才疏學淺,不對的地方還望斧正,也歡迎關注我的簡書,名稱為 肥朝