Dubbo調(diào)用流程一覽

前言

Apache Dubbo作為一款高性能的Java RPC框架愕宋,在國內(nèi)服務(wù)化體系的演進過程中扮演了一個非常重要的角色,被大量公司廣泛使用结榄。

臨近年關(guān)中贝,或許有小伙伴有著尋找新機會的想法,那么在面試過程中很可能會常常見到這樣一個問題:

你了解Dubbo嗎 ? 能不能講一講它的調(diào)用流程臼朗。

對于不了解的盆友而言邻寿,無疑會降低印象分蝎土;如果僅僅會使用,其實也不太夠绣否,最起碼我們要了解它的基本原理誊涯。

本文試圖從Dubbo使用者的角度上,結(jié)合流程圖和關(guān)鍵代碼把相應(yīng)知識點串聯(lián)起來蒜撮,回答我們上面的問題暴构。

一、服務(wù)提供者

從程序開發(fā)者的角度來看淀弹,我們要先有服務(wù)提供者丹壕。通常,我們在具體接口的實現(xiàn)上標(biāo)注Dubbo的Service注解薇溃。

package com.viewscenes.producer.dubbo;
import org.apache.dubbo.config.annotation.Service;
import com.viewscenes.common.service.DubboUserService;
@Service
public class DubboUserServiceImpl implements DubboUserService {
}

這個實現(xiàn)類在Dubbo中對應(yīng)的解析類為ServiceBean菌赖,它負責(zé)將這個實現(xiàn)對外暴露成一個服務(wù)。過程如下:

Dubbo服務(wù)暴露過程

結(jié)合上圖來看沐序,我們可以說在提供者端琉用,暴露一個服務(wù)的過程如下:

首先,ServiceConfig類引用對外提供服務(wù)的實現(xiàn)類ref (如DubboUserServiceImpl) 策幼, 然后通過ProxyFactoty接口的擴展實現(xiàn)類的getInvoker()方法使用ref生成一個AbstractProxyInvoker實例邑时,到此就完成了具體服務(wù)到Invoker的轉(zhuǎn)化。

接下來特姐,通過Dubbo協(xié)議的export()方法晶丘,將Invoker轉(zhuǎn)化為Exporter。那么在這里唐含,就會先啟動Netty Server的監(jiān)聽浅浮,然后將服務(wù)注冊到服務(wù)注冊中心。

在這里捷枯,我們必須要注意的是滚秩,作為服務(wù)提供者端,已經(jīng)通過Netty開啟了TCP端口的監(jiān)聽淮捆。那么郁油,當(dāng)消費者調(diào)用的時候,通過一系列Netty Handler處理器攀痊,就會調(diào)用到DubboProtocol > ExchangeHandler.reply()桐腌。

在這個方法里,就是一個反推的過程苟径。通過要調(diào)用的服務(wù)接口名稱哩掺,找到Exporter ,然后再獲取到Invoker對象涩笤。

Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException {
    int port = channel.getLocalAddress().getPort();
    String path = inv.getAttachments().get(PATH_KEY);
    String serviceKey = serviceKey(port, path, inv.getAttachments().get(VERSION_KEY),  inv.getAttachments().get(GROUP_KEY));
    DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);
    return exporter.getInvoker();
}

從上面的分析中我們已經(jīng)知道嚼吞,這里的Invoker對象是根據(jù)服務(wù)實現(xiàn)類生成的一個AbstractProxyInvoker實例。它最終會調(diào)用到wrapper.invokeMethod()方法蹬碧。這里的wrapper類是通過Javassist生成的舱禽,在內(nèi)存中的類,它的核心方法長這樣:

image

Dubbo會給每個服務(wù)提供者的實現(xiàn)生成一個Wrapper類恩沽。當(dāng)接收到消費方的請求后誊稚,根據(jù)傳遞的方法名和參數(shù),Wrapper類調(diào)用服務(wù)提供者的接口類實現(xiàn)即可罗心。這樣做的目的主要是為了減少反射的調(diào)用里伯。

二、服務(wù)消費者

在服務(wù)消費者端渤闷,我們直接引用一個接口即可疾瓮。

@Reference
DubboUserService userService;

或許你可能要問,為啥只注入了這么一個普通的接口飒箭,就可以調(diào)用到遠端的服務(wù)呢 狼电?

我們想想在 Mybatis中的Dao接口和XML文件里的SQL是如何建立關(guān)系的? 這個問題中弦蹂,它們是怎么關(guān)聯(lián)起來的呢 肩碟?

說穿了還是Spring的功勞,或者說是Spring FactoryBean的功勞凸椿。

Dubbo中削祈,標(biāo)注了@Reference的接口,都會被當(dāng)成一個Factory Bean 脑漫,這個Bean一般都會返回一個代理對象髓抑,來屏蔽底層一些復(fù)雜的操作。比如Mybatis里的mapper接口和xml文件關(guān)聯(lián)窿撬,Dubbo中的網(wǎng)絡(luò)通信等启昧。

我們還是先來通過一張圖看看消費者端的具體過程:

服務(wù)引用

結(jié)合上圖來看,我們總結(jié)下服務(wù)引用的過程:

Reference注解標(biāo)注的Dubbo接口劈伴,會被注冊成FactoryBean密末,并最終返回一個代理對象。

在創(chuàng)建代理的過程中跛璧,會調(diào)用其他方法構(gòu)建以及合并 Invoker 實例严里。

首先,調(diào)用DubboProtocol的refer方法追城,返回DubboInvoker對象刹碾。在這里,比較重要的是獲取客戶端實例座柱。比如NettyClient迷帜,Dubbo要依靠它來進行網(wǎng)絡(luò)通信物舒。

然后,還需要將多個服務(wù)提供者實例合并成一個戏锹,這是集群容錯機制的實現(xiàn)冠胯。

最后,通過JavassistProxyFactory創(chuàng)建代理并返回锦针。在這里荠察,它的處理器是InvokerInvocationHandler ,這就意味著奈搜,當(dāng)我們在消費者端調(diào)用一個Dubbo接口的時候悉盆,實際上會調(diào)用到InvokerInvocationHandler.invoke()方法,在這里面Dubbo完成了譬如集群容錯馋吗、負載均衡焕盟、調(diào)用遠程方法的一系列動作。

Dubbo消費者發(fā)送請求的時候耗美,最終會調(diào)用到DubboInvoker中的方法京髓。在這里,會完成具體的請求邏輯商架,比如發(fā)送請求數(shù)據(jù)堰怨。

final class HeaderExchangeChannel implements ExchangeChannel {
    //創(chuàng)建請求消息對象
    Request req = new Request();
    req.setVersion(Version.getProtocolVersion());
    req.setTwoWay(true);
    req.setData(request);
    
    //創(chuàng)建Future,用于獲取返回結(jié)果
    DefaultFuture future = DefaultFuture.newFuture(this.channel, req, timeout, executor);
    try {
        //通過Netty客戶端發(fā)送數(shù)據(jù)
        this.channel.send(req);
        return future;
    } catch (RemotingException var7) {
        future.cancel();
        throw var7;
    }
}

三蛇摸、請求-響應(yīng)過程

Dubbo請求響應(yīng)過程
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末备图,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子赶袄,更是在濱河造成了極大的恐慌揽涮,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饿肺,死亡現(xiàn)場離奇詭異蒋困,居然都是意外死亡,警方通過查閱死者的電腦和手機敬辣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門雪标,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人溉跃,你說我怎么就攤上這事村刨。” “怎么了撰茎?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵嵌牺,是天一觀的道長。 經(jīng)常有香客問我,道長逆粹,這世上最難降的妖魔是什么募疮? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮僻弹,結(jié)果婚禮上酝锅,老公的妹妹穿的比我還像新娘。我一直安慰自己奢方,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布爸舒。 她就那樣靜靜地躺著蟋字,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扭勉。 梳的紋絲不亂的頭發(fā)上鹊奖,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機與錄音涂炎,去河邊找鬼忠聚。 笑死,一個胖子當(dāng)著我的面吹牛唱捣,可吹牛的內(nèi)容都是我干的两蟀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼震缭,長吁一口氣:“原來是場噩夢啊……” “哼赂毯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拣宰,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤党涕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后巡社,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膛堤,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年晌该,在試婚紗的時候發(fā)現(xiàn)自己被綠了肥荔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡气笙,死狀恐怖次企,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情潜圃,我是刑警寧澤缸棵,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站谭期,受9級特大地震影響堵第,放射性物質(zhì)發(fā)生泄漏吧凉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一踏志、第九天 我趴在偏房一處隱蔽的房頂上張望阀捅。 院中可真熱鬧,春花似錦针余、人聲如沸饲鄙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忍级。三九已至,卻和暖如春伪朽,著一層夾襖步出監(jiān)牢的瞬間轴咱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工烈涮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留朴肺,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓坚洽,卻偏偏與公主長得像戈稿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子酪术,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

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