概述
?????????上文消費(fèi)端服務(wù)調(diào)用中描述了發(fā)起一次遠(yuǎn)程調(diào)用的調(diào)用鏈,解析到了觸發(fā)了Netty的outBound寫事件writeAndFlush,將請求編碼發(fā)送,但一次遠(yuǎn)程調(diào)用其實并沒有真正完成,完整的一次遠(yuǎn)程調(diào)用還應(yīng)包括接受服務(wù)端返回數(shù)據(jù),將其返回給業(yè)務(wù)方。本文會繼續(xù)上文做余下工作的解析。
?????????在服務(wù)端,據(jù)前面對Netty的分析可知,NioEventLoop會監(jiān)聽OP_READ事件,收到OP_READ事件之后,會對其進(jìn)行處理,然后觸發(fā)ChannelRead入站事件,在pipiline中傳播,會先經(jīng)過解碼handler做解碼操作,然后會傳播到NettyServerHandler做真正的邏輯處理。
?????????消費(fèi)端的接收響應(yīng)結(jié)果實踐邏輯與服務(wù)端大致相同,而且沒有服務(wù)端的請求響應(yīng)過程甚至更為簡單一些,下文會分開介紹。
服務(wù)端請求響應(yīng)源碼分析
?????????服務(wù)端的請求響應(yīng)源碼分析從NettyServerHandler#channelRead方法開始,代碼實現(xiàn)如下:

?????????此處實現(xiàn)較為簡單,主要是獲取NettyChannel對象,此處的handler為NettyServer,跟進(jìn)會進(jìn)入AbstractPeer#received,然后進(jìn)入MultiMessageHandler#received,因為這兩個方法實現(xiàn)非常簡單,就不再代碼展開,直接跟進(jìn)到HeartbeatHandle#received,代碼實現(xiàn)如下:
?????????此處主要是對心跳請求的處理,心跳請求則新建response設(shè)置requestid和心跳返回事件,將其返回,如果是心跳響應(yīng)直接return。如果是正常遠(yuǎn)程調(diào)用則進(jìn)入AllChannelRead#received方法,實現(xiàn)代碼如下:
?????????前面的操作都是I/O線程處理,此處將派發(fā)到業(yè)務(wù)線程池去執(zhí)行,因為I/O線程數(shù)量有限,因此比較耗時的業(yè)務(wù)操作一般交由業(yè)務(wù)線程池處理,以免阻塞I/O線程。
?????????Dubbo中提供了5種線程派發(fā)策略(all,direct,message,execution,connection),來決定哪些操作線程由業(yè)務(wù)線程池處理,哪些操作由I/O線程處理。具體規(guī)則如下:
?????????????all 所有消息都派發(fā)到線程池,包括請求,響應(yīng),連接事件,斷開事件,心跳等。
?????????????direct 所有消息都不派發(fā)到線程池,全部在 IO 線程上直接執(zhí)行。
?????????????message 只有請求響應(yīng)消息派發(fā)到線程池,其它連接斷開事件,心跳等消息,直接在 IO 線程上執(zhí)行。
?????????????execution 只請求消息派發(fā)到線程池,不含響應(yīng),響應(yīng)和其它連接斷開事件,心跳等消息,直接在 IO 線程上執(zhí)行。
?????????????connection 在 IO 線程上,將連接斷開事件放入隊列,有序逐個執(zhí)行,其它消息派發(fā)到線程池。
?????????繼續(xù)往下跟進(jìn),就要進(jìn)入業(yè)務(wù)線程,代碼跟蹤到ChannelEventRunnable#run方法,代碼實現(xiàn)如下:
?????????在上面新建ChannelEventRunnable對象時寫入了RECIVED狀態(tài),所以此處進(jìn)入DecodeHandler#received,實現(xiàn)代碼如下:
?????????消息解碼操作,因為此前已經(jīng)在解碼handler中做過解碼操作,所以此處不會執(zhí)行具體解碼邏輯,直接跳過,繼續(xù)跟進(jìn)會進(jìn)入HeaderExchangeHandler#received方法,代碼實現(xiàn)如下:
?????????主要對消息類型以及雙向還是單向進(jìn)行分類處理,因為此處是響應(yīng)消費(fèi)端的請求,所以進(jìn)入handleRequest方法,實現(xiàn)代碼如下:
?????????其實到了這個地方就能很清楚的看出服務(wù)端響應(yīng)請求的整體邏輯,構(gòu)造response,處理消費(fèi)端發(fā)來的請求,將結(jié)果回寫到response中,然后調(diào)用channel.send()發(fā)送給消費(fèi)端,發(fā)送消息在消費(fèi)端已經(jīng)分析過一次,所以這里看到了這個channel.send基本可以盲猜消費(fèi)端也有一個handler重寫了channelRead方法,等待處理服務(wù)端返回的結(jié)果。
?????????對handler.reply方法作展開,因為此處是Dubbo協(xié)議,所以跟進(jìn)到DubboProtocol#reply方法,代碼實現(xiàn)如下:
?????????前面在分析ServiceBean服務(wù)暴露過程中描述過,最終會將服務(wù)Invoker轉(zhuǎn)換根據(jù)對應(yīng)協(xié)議轉(zhuǎn)換成exporter放到exporterMap中,此處就是根據(jù)消費(fèi)發(fā)來的請求消息取出,執(zhí)行其invoke方法。
?????????執(zhí)行invoke方法之后也會觸發(fā)攔截器鏈,這里不再展開描述,直接跟進(jìn)到最后的AbstractProxyInvoker#invoke方法,實現(xiàn)代碼如下:
?????????到了這里終于到了執(zhí)行我們自己寫的service的時候,doInvoke方法默認(rèn)調(diào)用的JavassistProxyFactory返回的AbstractProxyInvoker中重寫的doInvoke方法,這里貼一下代碼:
?????????這里就看到了invokeMethod方法,獲得結(jié)果后,調(diào)用wrapWithFuture方法獲取future對象,這里主要對異步調(diào)用做處理,如果是異步則獲取異步Future對象,如果不是這直接以執(zhí)行結(jié)果作為result創(chuàng)建一個完成的future,然后是回調(diào)構(gòu)建異步結(jié)果對象asyncRpcResult,然后執(zhí)行返回以及回調(diào),最終數(shù)據(jù)發(fā)送給消費(fèi)端,同樣是觸發(fā)writeAndFlush出站寫事件。
消費(fèi)端異步回寫響應(yīng)結(jié)果
?????????上文中我們盲猜過,消費(fèi)端肯定有一個handler重寫了channelRead方法用于接收服務(wù)端的響應(yīng)結(jié)果,所以,進(jìn)入NettyClientHandler中,就看到了盲猜的結(jié)果,代碼如下:

?????????看上去和服務(wù)端的長得一樣,其實,不光長得一樣,后續(xù)流程也都一樣,一直到HeaderExchangeHandler#received方法,進(jìn)入handleResponse方法,才開始實現(xiàn)其寫回結(jié)果的邏輯,再貼一遍HeaderExchangeHandler#received方法,代碼如下:
?????????此處進(jìn)入了handleResponse方法,代碼實現(xiàn)如下:

?????????可以看到直接調(diào)用了DefaultFuture#received方法,具體實現(xiàn)如下:
?????????此處會根據(jù)消費(fèi)端傳過來的requestId從保存future對象的map中獲取對應(yīng)的future,設(shè)置結(jié)果并標(biāo)記完成,此處再貼一下doReceived方法的實現(xiàn),代碼如下:
?????????根據(jù)返回結(jié)果狀態(tài),標(biāo)記future對象的完成。上篇文章中調(diào)用get方法阻塞等帶返回結(jié)果的就可以繼續(xù)往下執(zhí)行了。
?????????到這里才算完成了一次完整的遠(yuǎn)程調(diào)用。