天天看點

dubbo源碼五:服務調用過程

文章目錄

      • 一、Cluster層
      • 二、Protocol 層
        • 1.ConsumerContextFilter 的invoke 方法
        • 2.FutureFilter 的invoke 方法
        • 3.MonitorFilter中的invoke方法
        • 4.DubboInvoker中invoke方法

消費端代碼示例(參考incubator-dubbo源碼中dubbo-demo子產品):

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
context.start();
DemoService demoService = (DemoService) context.getBean("demoService”);

 // 調用遠端方法
String hello = demoService.sayHello("world");
System.out.println(hello);
           

以dubbo分層概念來了解消費端調用過程:

dubbo源碼五:服務調用過程

服務端啟動後,消費端引用服務端的接口類會生成一個代理類,即生成InvokerInvocationHandler(invoker)對象執行個體,是以在調用的時候,會直接調用 InvokerInvocationHandler 的 invoke 方法,

dubbo源碼五:服務調用過程
dubbo源碼五:服務調用過程
dubbo源碼五:服務調用過程

一、Cluster層

Cluster層作用:封裝多個提供者的路由及負載均衡,并橋接注冊中心,以Invoker為中心,擴充接口為Cluster、Directory、Router和LoadBalance。将多個服務提供方組合為一個服務提供方,實作對服務消費方來透明,隻需要與一個服務提供方進行互動。

根據 https://blog.csdn.net/zhuqiuhui/article/details/84075521 分析知這裡的 invoker 是 MockClusterInvoker 執行個體,即會調用 MockClusterInvoker 的invoke方法,該方法首先判斷directory中的url是否含有mock值的設定,若沒有設定預設值false。這裡的directory中的url的變量是:

Debug,如下:

dubbo源碼五:服務調用過程

其中 this.invoker變量值如下:

dubbo源碼五:服務調用過程

上面會調用FailOverClusterInvoker.invoke(),即會調用其父類AbstractClusterInvoker.invoke()的方法。如下:

Debug-1:

dubbo源碼五:服務調用過程

Debug-1 分成以下幾個過程:

1. 檢查RPC Cluster invoker中要執行的接口是否被銷毀,若銷毀,則抛出異常。

dubbo源碼五:服務調用過程

2. 在調用提供者之前,會擷取目前線程臨時變量裡的RpcContext對象,再将RpcContext對象裡的參數設定到Invocation對象。

dubbo源碼五:服務調用過程

RpcContext 是一個臨時狀态持有者,每當發請求或者收到請求的時候RpcContext都會發生變化。例如A調用B,然後B調用C,在服務B中,在B調用C之前,RpcContext儲存了A調用B的參數。當B調用C的時候,RpcContext儲存了B調用C的參數。從源碼上看RpcContext對象是綁定線上程臨時變量LOCAL上,是以可以通過線程臨時變量來擷取到RpcContext的相關參數值。

3. 列出所有的Invoker

dubbo源碼五:服務調用過程
dubbo源碼五:服務調用過程

這裡可以看到 directory執行個體是 RegistryDirectory 的執行個體,會調用其父類的list方法,即如下:

dubbo源碼五:服務調用過程

上面走到RegistryDirectory的doList方法中,其中RegistryDirectory是在消費端服務啟動過程中自動會生成RegistryDirectory執行個體,對應的屬性也初始化完成了,即在消費端啟動過程時,把方法和對應的invoker關系存放到了RegistryDirectory中的methodInvokerMap屬性中(參考:https://blog.csdn.net/zhuqiuhui/article/details/84075521),是以這裡,如下:

dubbo源碼五:服務調用過程

其中傳回的 invokers 清單如上面的變量。

4. 擷取方法上配置的負載均衡政策,若沒有配置,選擇預設的政策

dubbo源碼五:服務調用過程

常用的配置方法如下:

<dubbo:reference interloadbalance="roundrobin"/>
           
dubbo源碼五:服務調用過程

這裡傳回的 loadbalance 的執行個體是 RandomLoadBalance 的執行個體。

5. 幂等操作,即在異步操作中會預設加上invocation ID,不作分析

6. 方法調用

dubbo源碼五:服務調用過程

會走到 FailOverClusterInvoker 中的 doInvoke 方法中,即:

dubbo源碼五:服務調用過程

該方法首先使用負載均衡政策選擇合适的invoker(不再分析),然後再進行invoker調用,其中invoker變量如下:

dubbo源碼五:服務調用過程

上面變量的第一行可以看出 invoker 執行個體是InvokerDelegate執行個體對象,調用其invoke方法會走到InvokerWrapper的invoke方法,由于InvokerDelegate執行個體對象中的invoker内部屬性是 Invoker 接口的匿名實作,其泛型是ProtocolFilterWrapper類,即如上圖中的”[email protected]”,是以會調用”[email protected]”執行個體invoke方法,看其内部實作:

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
    if (!filters.isEmpty()) {
        for (int i = filters.size() - 1; i >= 0; i--) {
            final Filter filter = filters.get(i);
            final Invoker<T> next = last;
            last = new Invoker<T>() {

                @Override
                public Class<T> getInterface() {
                    return invoker.getInterface();
                }

                @Override
                public URL getUrl() {
                    return invoker.getUrl();
                }

                @Override
                public boolean isAvailable() {
                    return invoker.isAvailable();
                }

                @Override
                public Result invoke(Invocation invocation) throws RpcException {
                    return filter.invoke(next, invocation);
                }

                @Override
                public void destroy() {
                    invoker.destroy();
                }

                @Override
                public String toString() {
                    return invoker.toString();
                }
            };
        }
    }
    return last;
}
           

調用的是filter的invoke方法(其中的filter執行個體是ConsumerContextFilter執行個體),首先會調用 ConsumerContextFilter 的 invoke 方法,在ConsumerContextFilter 的 invoke 方法中再調用 FutureFilter 的invoke方法,最後在 FutureFilter 的invoke方法中調用 MonitorFilter 的 invoke 方法,MonitorFilter 的 invoke 方法中會調用DubboInvoker 的invoke方法。

二、Protocol 層

Protocol層作用:封裝RPC調用,以Invocation和Result為中心,擴充接口為Protocol、Invoker和Exporter。Protocol是服務域,它是Invoker暴露和引用的主功能入口,它負責Invoker的生命周期管理。Invoker是實體域,它是Dubbo的核心模型,其它模型都向它靠擾,或轉換成它,它代表一個可執行體,可向它發起invoke調用,它有可能是一個本地的實作,也可能是一個遠端的實作,也可能一個叢集實作。

1.ConsumerContextFilter 的invoke 方法

dubbo源碼五:服務調用過程

這裡首先對 RpcContext 進行資訊設定,其後清空sever上下文,再對調用後的結果進行後處理(即postProcessResult方法,主要設定一些要傳遞的參數),在finally中清空了傳遞的參數(目的為下一次調用做準備)。postProcessResult參數中的invoker調用invoke方法會繼續調用下一個filter中的invoke方法,即FutureFilter中的invoke方法。從上面過程可以看出主要對 RpcContext 内容進行設定。

2.FutureFilter 的invoke 方法

dubbo源碼五:服務調用過程

主要做一些異步回調工作,其中 invoker.invoke方法會調用MonitorFilter中的invoke方法

3.MonitorFilter中的invoke方法

dubbo源碼五:服務調用過程

MonitorFilter會做下監控的處理。會調用 DubboInvoker中invoke方法。

4.DubboInvoker中invoke方法

dubbo源碼五:服務調用過程

走完上述方法就完成整個方法的調用過程。

繼續閱讀