Dubbo 靠它嶄露頭角

Hola绍昂,我是 yes佣盒。

經(jīng)過了 RPC 核心和 Dubbo 微內(nèi)核兩篇文章后,今天終于要稍稍深入一波 Dubbo 了檐春。

作為一個(gè)通用的 RPC 框架逻淌,性能是很重要的一環(huán),而易用性和擴(kuò)展性也極為重要疟暖。

簡單地卡儒、無侵入式地?cái)U(kuò)展和定制 RPC 各階段功能是很多團(tuán)隊(duì)的述求,Dubbo 就滿足了這些需求俐巴。

它通過微內(nèi)核設(shè)計(jì)和 SPI 擴(kuò)展骨望,使得一些有特殊需求的業(yè)務(wù)團(tuán)隊(duì)可以在 Dubbo 中實(shí)現(xiàn)自己的擴(kuò)展,而不需要修改源碼欣舵。

Dubbo 的成功離不開這樣的設(shè)計(jì)擎鸠,今天咱們就來盤一盤 Dubbo 是如何實(shí)現(xiàn)無侵入擴(kuò)展的,其間還會(huì)看到 Dubbo 的 IOC 和 AOP缘圈。

還有先打個(gè)預(yù)防針劣光,今天的內(nèi)容代碼有點(diǎn)多的,畢竟想要深入剖析糟把,源碼必不可少绢涡,剛好也順帶提一下看源碼的小技巧。

所以建議電腦上看遣疯,更加清晰和舒適雄可。

還有如果有沒看過源碼的同學(xué),來緊跟 Dubbo 這個(gè)系列吧缠犀,到時(shí)候再也不怕被面試官問看過源碼沒了数苫。

SPI

Dubbo 就是利用 SPI (Service Provider Interface)來實(shí)現(xiàn)擴(kuò)展機(jī)制的。

這個(gè) SPI 想必你們都很熟悉辨液,在大學(xué)寫數(shù)據(jù)庫大作業(yè)的時(shí)候就碰到了文判,訪問數(shù)據(jù)庫需要用到 java.sql.Driver

市面上的數(shù)據(jù)庫五花八門室梅,每個(gè)數(shù)據(jù)庫廠商都有自己的實(shí)現(xiàn)戏仓,所以肯定需要定制一個(gè)接口疚宇,這樣我們面向接口編程即可

而具體的實(shí)現(xiàn)則可以通過配置來加載赏殃,JDK SPI 這時(shí)候就派上用場了敷待。

其實(shí)一點(diǎn)都不神奇,就是約定一個(gè)地方仁热,加載的時(shí)候就去那個(gè)地方找實(shí)現(xiàn)類榜揖。

約定一個(gè)地方直白點(diǎn)說就是代碼里面寫死了一個(gè)目錄,這個(gè)目錄就是 META-INF/services/抗蠢。

然后在這個(gè)目錄下創(chuàng)建一個(gè)文件举哟,用接口全限定名來命名,文件內(nèi)容就是實(shí)現(xiàn)類的全限定名迅矛。

到時(shí)候要實(shí)現(xiàn)類就根據(jù)接口名來這里找妨猩,然后實(shí)例化就行了。

挺簡單的吧秽褒,這就是 JDK SPI壶硅,但是它不滿足 Dubbo 的需求。

因?yàn)?Dubbo 把自身的一些實(shí)現(xiàn)也剝離出來成為擴(kuò)展销斟,而這些實(shí)現(xiàn)還是有點(diǎn)多的庐椒,也不需要全部用上。

如果用 JDK SPI 會(huì)把配置文件里面的類全部加載蚂踊,這就導(dǎo)致資源的浪費(fèi)约谈。用的時(shí)候還需要遍歷過去才能找到對應(yīng)的實(shí)現(xiàn)。

所以 Dubbo 就在 JDK SPI 的基礎(chǔ)上實(shí)現(xiàn)了個(gè) Dubbo 的 SPI犁钟,可以根據(jù)指定的名稱按需加載實(shí)現(xiàn)類棱诱,比如拿 Cluster 來說就有這么多實(shí)現(xiàn)類。

約定的地方改了一下特纤,一共有三個(gè)目錄。

  • META-INF/dubbo/internal/ :這里是存放 Dubbo 內(nèi)部使用的 SPI 配置文件侥加。
  • META-INF/dubbo/ :這里是存放用戶自定義 SPI 配置文件捧存。
  • META-INF/services/:兼容 JDK SPI

然后文件里面的內(nèi)容是key=value形式,這樣就可以根據(jù) key 找到對應(yīng)的實(shí)現(xiàn)類担败。

然后在注解上可以配置默認(rèn)的 key 來選擇默認(rèn)的實(shí)現(xiàn)類昔穴,比如 Cluster 默認(rèn)的實(shí)現(xiàn)是 failover。

也可以通過 URL 參數(shù)來選擇實(shí)現(xiàn)類提前。

還有像 JDK SPI 擴(kuò)展點(diǎn)加載失敗的話吗货,連擴(kuò)展點(diǎn)名稱都拿不到,到時(shí)候報(bào)錯(cuò)也不知道哪里出問題狈网。

而 Dubbo SPI 則不會(huì)吃了錯(cuò)誤宙搬,并且還提供了擴(kuò)展點(diǎn)的自動(dòng)注入和 AOP 功能笨腥。

大致了解了 Dubbo SPI 之后,我們再來深入看看實(shí)現(xiàn)細(xì)節(jié)勇垛。

Dubbo SPI 實(shí)現(xiàn)細(xì)節(jié)

Dubbo SPI 的核心實(shí)現(xiàn)在 ExtensionLoader 中脖母,它負(fù)責(zé)擴(kuò)展點(diǎn)的加載和生命周期的維護(hù),類似 JDK SPI 的 ServiceLoader闲孤。

這里要先提一點(diǎn)看源碼的小技巧了谆级。

開源框架都會(huì)有單元測試,而單元測試?yán)锩婢蜁?huì)有我們看源碼時(shí)候想要的各種功能實(shí)現(xiàn)讼积,我們就可以從單元測試入手得知一些功能的劃分肥照,然后斷點(diǎn)調(diào)試逐漸深入。

比如今天文章的 ExtensionLoader 勤众,它在 dubbo-common 模塊中舆绎,咱們就進(jìn)入 test 來看看它測試用例怎么寫的。

當(dāng)然除了通過文件夾來找决摧,直接用文件名搜也行亿蒸。

找到了就好辦了,數(shù)據(jù)都是造好的掌桩,找到你想要調(diào)試的方法边锁,斷點(diǎn)一設(shè),箭頭一點(diǎn)波岛,這不就美滋滋了嗎茅坛?

好了,小技巧分享完畢则拷,回到 ExtensionLoader贡蓖,我們簡單點(diǎn)就用 Dubbo 單元測試的數(shù)據(jù)來看看實(shí)現(xiàn)。

有個(gè)叫 SimpleExt 的類煌茬,有三個(gè)實(shí)現(xiàn)斥铺,默認(rèn)的實(shí)現(xiàn)是 impl1。

再來看看 SPI 配置文件的內(nèi)容坛善,可以看到為了測試還故意寫了一些空格在配置文件中晾蜘。

然后現(xiàn)在如果要找 impl2 這個(gè)實(shí)現(xiàn),通過以下代碼調(diào)用即可眠屎。

SimpleExt ext = ExtensionLoader
    .getExtensionLoader(SimpleExt.class).getExtension("impl2") 

一個(gè)擴(kuò)展接口對應(yīng)有個(gè) ExtensionLoader剔交,找到對應(yīng)的 ExtensionLoader,然后再加載對應(yīng)名字的實(shí)現(xiàn)類改衩。

接下來會(huì)有源碼岖常,不過沒關(guān)系,還是很簡單的葫督,想要深入源碼這關(guān)必須過竭鞍。

可以看到getExtensionLoader 是靜態(tài)的板惑,里面邏輯也很簡單就是從緩存找接口對應(yīng)的 ExtensionLoader,找不到就新建一個(gè)返回笼蛛。

現(xiàn)在有了 ExtensionLoader洒放,咱們再來看看 getExtension 的邏輯务漩,來看看是如何通過擴(kuò)展點(diǎn) name 找到對應(yīng)的實(shí)現(xiàn)類的符匾。

可以看到又是有個(gè)緩存操作,邏輯非常簡單喻括,先去緩存找實(shí)例惋戏,如果沒有則創(chuàng)建實(shí)例领追。

要說細(xì)節(jié)就是用到了雙檢鎖,然后用 holder 來保證可見性和防止指令重排响逢。應(yīng)該看到注釋上的 holder 構(gòu)造了吧绒窑,volatile 和雙檢鎖的搭配,這里就不深入了舔亭。

我們來看看 createExtension些膨,這是要?jiǎng)?chuàng)建擴(kuò)展點(diǎn)了,代碼有點(diǎn)長钦铺,但是我都做了相應(yīng)的注釋订雾,包括綠色的注釋。

邏輯還是很簡單的矛洞,詳細(xì)的代碼沒有具體展示洼哎,我先口述一下。

  1. 通過接口類名去三個(gè)目錄找到對應(yīng)的文件沼本。
  2. 解析文件內(nèi)容生成 class 對象噩峦,然后緩存到 cachedClasses 中。
  3. 然后通過 name 去 cachedClasses 中找到對應(yīng)的 class 對象抽兆。
  4. 去緩存 EXTENSION_INSTANCES 看看是否已經(jīng)實(shí)例化過了识补。
  5. 沒有的話就實(shí)例化,然后調(diào)用 injectExtension 實(shí)現(xiàn)自動(dòng)注入辫红。
  6. 再通過 cachedWrapperClasses 實(shí)現(xiàn)包裝凭涂,將最后的包裝類返回。

有幾點(diǎn)不清晰沒關(guān)系厉熟,咱們接著分析导盅,腦海中先大概知道要做什么较幌,然后再來看看具體是怎么做的揍瑟。

源碼中的 loadDirectory 就是去目錄找文件,然后解析乍炉,最終會(huì)調(diào)用 loadClass绢片,這個(gè)方法很關(guān)鍵滤馍,我們詳細(xì)分析一下,為了便于觀看底循,刪除了一些代碼巢株。

自適應(yīng)咱們先略過,只要知道是在這里記錄的即可熙涤。

然后上面提到的 AOP 相關(guān)的 cachedWrapperClasses 就是在這里記錄的阁苞,如果判斷它是包裝類呢?

簡單粗暴但是有效祠挫,只要有當(dāng)前類作為構(gòu)造器參數(shù)的類就是包裝類那槽,有點(diǎn)拗口,多讀幾遍就理解了等舔。

現(xiàn)在我們再回過頭來看看這段代碼骚灸,Dubbo 的 AOP。

把擴(kuò)展類對應(yīng)的包裝類都記錄下來放在 cachedWrapperClasses 中慌植,然后在實(shí)例化擴(kuò)展類的時(shí)候就一層一層的把擴(kuò)展類包起來甚牲,最終返回的就是包裝類。

為什么說這就是 AOP 呢蝶柿?因?yàn)榈扔诎岩恍┻壿嬊羞M(jìn)了擴(kuò)展實(shí)現(xiàn)類中丈钙。

其實(shí)就是把擴(kuò)展對象的公共邏輯移到包裝類中,我們看下單元測試的例子就很清晰了只锭。

從圖中可以看到有兩個(gè)擴(kuò)展實(shí)現(xiàn)類著恩,兩個(gè)包裝類,具體邏輯就不看了蜻展,不是重點(diǎn)喉誊,配置文件如下:

然后再看一下單元測試的運(yùn)行結(jié)果,可以看到最終返回的其實(shí)是 Ext5Wrapper1 對象纵顾,并且它還包著 wrapper2 對象伍茄。

所以 echo 方法的調(diào)用鏈就是:
Ext5Wrapper1 ->Ext5Wrapper2->Ext5impl1

也就起到了 AOP 的效果。

接下來我們再來看看 injectExtension施逾,是如何實(shí)現(xiàn) Dubbo 的自動(dòng)注入敷矫。

看了代碼之后是不是有點(diǎn)失望,就這汉额?

是的就是這么樸素地判斷有沒有 set 方法曹仗,然后根據(jù)參數(shù)找到對象,執(zhí)行 set 方法注入即可蠕搜。

所以說源碼之下無秘密怎茫,看起來好像很高級(jí)的東西,就這。

上面代碼中還有個(gè)objectFactory.getExtension()轨蛤,這個(gè)和擴(kuò)展自適應(yīng)有關(guān)系蜜宪,還有個(gè)@Activate也沒說。

這些內(nèi)容還是有點(diǎn)多的祥山,也很重要圃验,感覺上可能還有點(diǎn)繞,所以單獨(dú)寫一篇說缝呕。

最后

Dubbo 就是靠自己實(shí)現(xiàn)的 SPI 機(jī)制把通信協(xié)議澳窑、序列化格式、負(fù)載均衡供常、路由策略等各部分抽出來作為插件照捡,實(shí)現(xiàn)擴(kuò)展和定制。

通過微內(nèi)核和SPI 機(jī)制來滿足用戶定制化的需求话侧,也保證了框架本身的穩(wěn)定性和可持續(xù)性栗精。

并且 Dubbo 自身也提供了很多已有的實(shí)現(xiàn),像各種路由策略等等瞻鹏。

所以說一個(gè)好的框架不僅自己功能要全悲立,還得對擴(kuò)展開放,這樣生態(tài)才會(huì)壯大新博。

今天的代碼還是有點(diǎn)多的薪夕,如果看不懂的建議下載源碼,跟著源碼調(diào)試幾遍就清晰了赫悄。

源碼這一步一定要邁過去原献,邁過去了之后就輕松了。

Dubbo 系列持續(xù)更新埂淮,敬請期待姑隅,有問題可以留言,我會(huì)盡量解答倔撞。

更多文章可看我的文章匯總:https://github.com/yessimida/yes 歡迎 star !


我是 yes讲仰,從一點(diǎn)點(diǎn)到億點(diǎn)點(diǎn),歡迎在看痪蝇、轉(zhuǎn)發(fā)鄙陡、留言,我們下篇見躏啰。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末趁矾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子给僵,更是在濱河造成了極大的恐慌毫捣,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異培漏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)胡本,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門牌柄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人侧甫,你說我怎么就攤上這事珊佣。” “怎么了披粟?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵咒锻,是天一觀的道長。 經(jīng)常有香客問我守屉,道長惑艇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任拇泛,我火速辦了婚禮滨巴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘俺叭。我一直安慰自己恭取,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布熄守。 她就那樣靜靜地躺著蜈垮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裕照。 梳的紋絲不亂的頭發(fā)上攒发,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機(jī)與錄音晋南,去河邊找鬼晨继。 笑死,一個(gè)胖子當(dāng)著我的面吹牛搬俊,可吹牛的內(nèi)容都是我干的紊扬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼唉擂,長吁一口氣:“原來是場噩夢啊……” “哼餐屎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起玩祟,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤腹缩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體藏鹊,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡润讥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盘寡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楚殿。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖竿痰,靈堂內(nèi)的尸體忽然破棺而出脆粥,到底是詐尸還是另有隱情,我是刑警寧澤影涉,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布变隔,位于F島的核電站,受9級(jí)特大地震影響蟹倾,放射性物質(zhì)發(fā)生泄漏匣缘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一鲜棠、第九天 我趴在偏房一處隱蔽的房頂上張望孵户。 院中可真熱鬧,春花似錦岔留、人聲如沸夏哭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽竖配。三九已至,卻和暖如春里逆,著一層夾襖步出監(jiān)牢的瞬間进胯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工原押, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胁镐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓诸衔,卻偏偏與公主長得像盯漂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子笨农,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 通過本文的學(xué)習(xí)就缆,可以了解 Dubbo SPI 的特性及實(shí)現(xiàn)原理,希望對大家的開發(fā)設(shè)計(jì)有一定的啟發(fā)性谒亦。 一竭宰、概述 S...
  • 本系列參考官網(wǎng)文檔空郊、芋道源碼的源碼解讀和《深入理解Apache Dubbo與實(shí)戰(zhàn)》一書。閱讀本文前可以參考閱讀下面...
    就這些嗎閱讀 410評論 0 0
  • Dubbo版本:2.7.5源碼下載地址:https://github.com/apache/dubbo/relea...
  • dubbo自定義SPI 為什么dubbo要自己設(shè)計(jì)一套SPI切揭? JDK標(biāo)準(zhǔn)的SPI會(huì)一次性實(shí)例化擴(kuò)展點(diǎn)所有實(shí)現(xiàn)狞甚,如...
    半個(gè)橙子閱讀 655評論 0 9
  • 推薦指數(shù): 6.0 書籍主旨關(guān)鍵詞:特權(quán)、焦點(diǎn)廓旬、注意力哼审、語言聯(lián)想、情景聯(lián)想 觀點(diǎn): 1.統(tǒng)計(jì)學(xué)現(xiàn)在叫數(shù)據(jù)分析嗤谚,社會(huì)...
    Jenaral閱讀 5,720評論 0 5