圖解Dubbo提供者部分重要的類關係

Dubbo的提供者發佈服務是一個比較複雜的過程。概括起來說,主要有以下幾步:
1.解析配置
2.導出服務

解析服務的過程略過。本文主要分析導出服務的過程,其中有一些比較重要的類,它們之間通過代理模式和裝飾器模式,巧妙組合在一起,實現了Dubbo的提供者的功能,本文通過畫圖來解釋它們。

導出服務又可以分爲以下幾步:

生成實現類的包裹對象即代理對象

假設我們定義了一個遠程調用的接口,那麼在提供者端就需要一個實現類來實現這個接口。同時爲了實現監控,回調等功能,當請求到達時,不能簡單根據類名和方法名去通過反射調用實現類。而是需要在此基礎上對類進行包裝,同時生成一系列代理對象。此外,Dubbo還通過責任鏈模式,實現了對請求的攔截處理鏈。概括起來,這個過程生成的類的關係圖如下所示
在這裏插入圖片描述
最裏層的ref代表接口的實現類,它是由用戶開發的。從內到外,是Dubbo框架自動進行的一層層的包裝。下面介紹一下其中比較重要的類或概念
1)Wrapper,是利用javassist字節碼工具生成的ref的動態代理類,它不僅對ref實現的接口的方法進行了包裝,同時也包裝了ref的實現類的各種屬性,方法的元數據等。
2)AbstractProxyInvoker是對Wrapper的包裝,它是Invoker接口的默認實現類,在這裏實際上是AbstractProxyInvoker類的一個抽象匿名子類。因爲Invoker在攔截處理鏈中代表實現類的執行者,所以需要將Wrapper再包裝爲一個Invoker。值得注意的是AbstractProxyInvoker的invoke方法和doInvoker方法。
首先看doInvoke方法

    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

這裏的T泛型代表ref的接口,proxy就是ref,可以看出先生成了上文說的Wrapper包裹類,之後生成了AbstractProxyInvoker的抽象子類。這裏的doInvoke方法就是通過wrapper去實際調用到ref裏的方法實現了。

再看invoke方法

    @Override
    public Result invoke(Invocation invocation) throws RpcException {
        try {
            Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
			CompletableFuture<Object> future = wrapWithFuture(value);
            CompletableFuture<AppResponse> appResponseFuture = future.handle((obj, t) -> {
                AppResponse result = new AppResponse();
                if (t != null) {
                    if (t instanceof CompletionException) {
                        result.setException(t.getCause());
                    } else {
                        result.setException(t);
                    }
                } else {
                    result.setValue(obj);
                }
                return result;
            });
            return new AsyncRpcResult(appResponseFuture, invocation);
        } catch (InvocationTargetException e) {
            if (RpcContext.getContext().isAsyncStarted() && !RpcContext.getContext().stopAsync()) {
                logger.error("Provider async started, but got an exception from the original method, cannot write the exception back to consumer because an async result may have returned the new thread.", e);
            }
            return AsyncRpcResult.newDefaultAsyncResult(null, e.getTargetException(), invocation);
        } catch (Throwable e) {
            throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

這個方法的第一行就是調用doInvoker方法。然後獲取到結果之後,就將這個結果通過CompletableFuture進行異步化。通過這裏我們看出,在框架層面Dubbo已經做到了完全的異步化,但是如果用戶的方法是同步方法的話,這裏還是會阻塞。如果要做到完全的異步化,可以將遠程接口的返回類型定義爲CompletableFuture。這樣可以做到從框架到應用的完全異步化,在某些場景可以進一步提升性能。
2)DelegateProviderMetaDataInvoker只是簡單包裝,同時保存了服務的配置元信息。
3)InvokeDelegate是對DelegateProviderMetaDataInvoker的進一步封裝,同時保存了註冊的服務URL對象。
4)往外的各個Filter就是爲了實現各種框架的必需功能或可選功能而嵌套的攔截鏈了。當請求進來時,會從EchoFilter開始向下穿越各個filter和代理對象,直至進入用戶自己的實現類。其中可能開啓某些功能時請求會在中途直接返回,而不繼續向下。比如如果是回聲測試,就會在EchoFilter就直接返回。

服務導出者類

在這裏插入圖片描述
這些類實現的接口是Exporter,代表了一個被導出的服務(即可以被遠程調用的接口服務)。
DubboExporter代表是由Dubbo協議導出;ListenerExporterWrapper的功能是集成了一個ExporterListener列表,在導出時進行回調。

綁定服務端的類

在這裏插入圖片描述
在完成了形式上的導出服務之後,最重要的一步就是綁定服務端,也就是對外界開放接收網絡連接,並且接收請求的能力。Dubbo底層默認是基於Netty的,所以最裏層是NettyServer,它封裝了通過Netty建立一個服務端的功能,外層是HeaderExchangeServer,它主要是封裝了一些端到端連接的功能,比如長連接的空閒檢測,在Dubbo框架層面管理連接等。DubboProtocolServer是進一步封裝。

連接或消息處理類

在上圖中,最裏層的MultiMessageHandler並不是代表綁定服務端的類。而是一個連接或消息處理類。因此因此這一組類
在這裏插入圖片描述
ExchangeHandlerAdapter裏層的其實是ExchangeHandlerAdapter這個類的抽象匿名子類,這個類只有一個方法,方法簽名爲

public CompletableFuture<Object> reply(ExchangeChannel channel, Object msg) throws RemotingException

它的實現類

@Override
        public CompletableFuture<Object> reply(ExchangeChannel channel, Object message) throws RemotingException {

            if (!(message instanceof Invocation)) {
                throw new RemotingException(channel, "Unsupported request: "
                        + (message == null ? null : (message.getClass().getName() + ": " + message))
                        + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
            }

            Invocation inv = (Invocation) message;
            Invoker<?> invoker = getInvoker(channel, inv);
            // need to consider backward-compatibility if it's a callback
            // 省略次要代碼
            RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
            Result result = invoker.invoke(inv);
            return result.thenApply(Function.identity());
        }

可見這個方法內部就是通過參數去獲取Invoker對象,進而調用實現類。這裏獲取到的實現類,就是上文的包裹了EchoFilter的Invoker實例。同時這裏reply方法返回類型是CompletableFuture,這是因爲前面介紹的AbstractProxyInvoker的invoke方法對調用結果進行了異步化。

HeaderExchangeHandler主要還是管理連接等。
DecodeHandler主要是對請求進行解碼。
AllChannelHandler是主要負責線程管理。
HeartbeatHandler主要負責心跳檢測。
MultiMessageHandler主要負責將Dubbo內部定義的多條消息的聚合消息進行拆分處理。

總結

本文簡單介紹了Dubbo提供者端發佈服務時的一些重要的類及其組合關係。在閱讀源碼,梳理流程時,抓住這些關鍵的類,可以有助於理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章