1. 程式人生 > >dubbo原始碼分析-RPC遠端呼叫模組與Remoting通訊模組協作細節

dubbo原始碼分析-RPC遠端呼叫模組與Remoting通訊模組協作細節

閱讀需要技能:

1.設計模式:理解代理模式。JDK動態代理類的使用。
2.設計模式:理解裝飾模式。
3.Netty網路通訊程式設計,server,handler,channel
4.瞭解Dubbo基本原理,Dubbo模組各層分包關係

Dubbo RPC 服務端提供服務實現細節

服務端提供服務過程主要分為兩部分:
暴露服務Exporter(用於向註冊中心註冊和包裝好提供服務的類) 和監聽服務(用於開啟socket偵聽服務,並接收客戶端發來的各種請求)

DubboProtocol類被用於服務端和消費端,其分別對應方法export 和refer,是RPC層和REMOTING層的橋樑

下圖是暴露服務的執行時序,注意此圖不是服務監聽執行結果並返回給客戶端過程
這裡寫圖片描述

由上圖知道兩大重要過程,
1是開啟socket通訊提供監聽客戶端請求
2是把暴露的服務註冊到註冊中心

DubboProtocol如何為服務端開啟socket通訊偵聽?

細節在DubboProtocol的openserver方法

 private ExchangeServer createServer(URL url) {
  ....
 private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
   public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
   ...
...} } ExchangeServer server; server = Exchangers.bind(url, requestHandler); .... return server; }

注意requestHandler,這是服務端偵聽到請求後由NettyHandler呼叫的方法

ExchangeHandler requestHandler的使用,服務端偵聽到請求後如何回撥該方法?

下面補充詳細呼叫過程。注意,在這個過程中,某些功能類在不斷在初始化構建,並且有些有裝飾模式不斷增強功能,這些構建好的包裝類,最終在監聽接收客戶端請求後觸發。
DubboProtocol.export(Invoker) line: 253
DubboProtocol.openServer(URL) line: 266
DubboProtocol.createServer(URL) line: 287
Exchangers.bind(URL, ExchangeHandler) line: 63
HeaderExchanger.bind(URL, ExchangeHandler) line: 41

這裡寫圖片描述

裝飾模式例子1:

new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));

可見,核心處理類在HeaderExchangeHandler,DecodeHandler是對其包裝。Transporters後來被ExtensionLoader預設載入為NettyTransporter,其也包含HeaderExchangeHandler,同理HeaderExchangeServer也包含HeaderExchangeHandler。

這裡寫圖片描述

繼續執行除錯例子,跳轉到下面程式碼。
裝飾模式例子2:
這裡寫圖片描述

new MultiMessageHandler(new HeartbeatHandler(ExtensionLoader.getExtensionLoader(Dispatcher.class)
                                        .getAdaptiveExtension().dispatch(handler, url)));

注意,ExtensionLoader.getExtensionLoader(Dispatcher.class)
.getAdaptiveExtension().dispatch(handler, url)) 生成AllChannelHandler

繼續執行除錯例子,跳轉到下面程式碼。

這裡寫圖片描述

可見HeaderExchangeHandler(實現ChannelHandler)被傳遞到NettyServer。
並且NettyServer的doOpen方法內容大部分就是Netty框架的基本應用程式碼,

 protected void doOpen() throws Throwable {
        ...
      ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
        ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
        final NettyHandler nettyHandler = new NettyHandler(getUrl(), this); //this包含requestHandler
       ...
}

回撥函式requestHandler被繫結在了Netty框架的監聽端,一旦有客戶端請求就自動觸發,這是Netty框架實現的。
至此,可以看到RPC層如何呼叫Remoting通訊模組了。本文通訊模組的例子取dubbo預設的Netty網路通訊框架。

DubboProtocol偵聽到客戶端請求時候究竟執行了什麼?

RPC通訊原理就是客戶端把請求執行的服務名字,呼叫方法名,以及方法引數通過socket傳送到服務端。服務端利用服務名字反射得到對應的服務類,並且呼叫服務類的方法,該方法由客戶端傳送過來指定的方法名,引數內容也是客戶端傳送過來的引數值。

這個觸發執行過程如下:
當有客戶端請求時候,
首先DecodeHandler.received進行解碼
然後HeaderExchangeHandler.handleRequest一直到NettyHandler的reply方法被觸發執行(NettyHandler包裝了requestHandler的reply方法),
最後執行完結果後通過channel.send傳送結果回客戶端。

如圖:
reply方法被執行:
這裡寫圖片描述

channel.send傳送結果回客戶端
這裡寫圖片描述

  • requestHandler的使用,這是服務端偵聽到請求後呼叫的方法(業務處理)
 private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
        public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
            if (message instanceof Invocation) {
                Invocation inv = (Invocation) message;
                Invoker<?> invoker = getInvoker(channel, inv);
      ...
       ...
                return invoker.invoke(inv);
            }
        }
}

注意,這裡的invoker是代理類代理了真正的服務impl類

  • 然後在代理類JdkProxyFactory或者JavassistProxyFactory的doInvoke(…)方法中執行,因為代理類生成invoker
    Dubbo的invoker.invoke(inv); –> AbstractProxyInvoker的doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()) –> JdkProxyFactory的doInvoke(…)

總結:

DubboProtocol 利用Netty開啟服務端監聽操作,繫結Handler,定義Handler業務邏輯
==>
…(省略)
==>
服務端接收使用者請求
HeaderExchangeHandler.received
==>
服務端處理使用者請求
HeaderExchangeHandler.handleRequest
==>
服務端傳送回覆到使用者
HeaderExchangeChannel.send(response);
==>
使用Netty框架傳送
NettyChannel.send
==>
傳送端Netty呼叫:

 ChannelFuture future = channel.write(message); //org.jboss.netty.channel.Channel channel;

延伸思考

基於上面詳細的程式碼呼叫鏈指示,相信大家對服務端和消費端如何通過通訊模組互動資訊有基本認識。下面問題留給大家思考:

  • DubboProtocol偵聽到客戶端請求執行完結果後向客戶端傳送了什麼?
  • DubboProtocol客戶端如何傳送請求?
  • DubboProtocol客戶端如何等待服務端應答?