dubbo源碼分析(二) 從dubbo協(xié)議分析Protocol層

上一篇我們簡單描述了dubbo服務暴露-服務引用的流程
這一篇我們從dubbo協(xié)議來具體分析一下Protocol層

export()過程

    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        URL url = invoker.getUrl();
        // export service.
        String key = serviceKey(url);
        DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
        //將exporter存到map里
        exporterMap.put(key, exporter);

        ...
        openServer(url);
        return exporter;
    }

    /**
     * 開啟服務
     *
     * @param url
     */
    private void openServer(URL url) {
        // find server.
        String key = url.getAddress();
        //client 也可以暴露一個只有server可以調用的服務。
        boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
        if (isServer) {
            ExchangeServer server = serverMap.get(key);
            if (server == null) {
                //map中不存在創(chuàng)建server
                serverMap.put(key, createServer(url));
            } else {
                //server支持reset,配合override功能使用
                server.reset(url);
            }
        }
    }
     /**
     * 創(chuàng)建服務
     *
     * @param url
     * @return
     */
    private ExchangeServer createServer(URL url) {
        ...
        ExchangeServer server;
        try {//啟動服務監(jiān)聽 傳入了requestHandler
            //當收到客戶端調用時會調用requestHandler.received()方法
            server = Exchangers.bind(url, requestHandler);
        } catch (RemotingException e) {
            throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
        }
        ...
        return server;
    }
    private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {

        @Override
        public void received(Channel channel, Object message) throws RemotingException {
            if (message instanceof Invocation) {
                reply((ExchangeChannel) channel, message);
            } else {
                super.received(channel, message);
            }
        }

   
        public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
            if (message instanceof Invocation) {
                Invocation inv = (Invocation) message;
                //獲取到對應的invoker
                Invoker<?> invoker = getInvoker(channel, inv);
                ...
                //根據(jù) Invocation 調用信息,調用真正服務實現(xiàn)
                return invoker.invoke(inv);
            }
           ...
        }
        ...
    };
    /**
     * 根據(jù)請求參數(shù)獲取到對應的服務端invoker
     *
     * @param channel
     * @param inv
     * @return
     * @throws RemotingException
     */
    Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException {
        int port = channel.getLocalAddress().getPort();
        String path = inv.getAttachments().get(Constants.PATH_KEY);
        ...
        //生成serviceKey
        String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv
                .getAttachments().get(Constants.GROUP_KEY));
        //從map中找到exporter
        DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);
        ...
        return exporter.getInvoker();
    }

概括一下:
export()就是根據(jù)服務url生成Exporter并存在map中,然后暴露服務,設置回調.
當客戶端調用請求時進入回調,根據(jù)請求url找到存在map中的Exporter,
最后用Exporter中的Invoker調用真正的服務

注意:服務端客戶端都存在Invoker對象,但兩者有所區(qū)別.
客戶端Invoker用于溝通服務端實現(xiàn)遠程調用 如:DubboInvoker
服務端Invoker用于調用真正服務實現(xiàn) 一般都繼承AbstractProxyInvoker 見下述代碼段

  com.alibaba.dubbo.rpc.proxy.jdk.JdkProxyFactory#getInvoker
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName, 
                                      Class<?>[] parameterTypes, 
                                      Object[] arguments) throws Throwable {
                Method method = proxy.getClass().getMethod(methodName, parameterTypes);
                return method.invoke(proxy, arguments);
            }
        };
    }

refer()過程

    public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException            {
        // create rpc invoker.
        DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
        invokers.add(invoker);
        return invoker;
    }

refer()就是根據(jù)url生成Invoker

調用過程

來看DubboInvoker.doInvoke()方法

    @Override
    protected Result doInvoke(final Invocation invocation) throws Throwable {
        RpcInvocation inv = (RpcInvocation) invocation;
        ...
        try {
            boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
            boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);//是否有返回值
            int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY,Constants.DEFAULT_TIMEOUT);
            if (isOneway) {//無返回值
                boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
                currentClient.send(inv, isSent);
                RpcContext.getContext().setFuture(null);
                return new RpcResult();
            } else if (isAsync) {//異步
                ResponseFuture future = currentClient.request(inv, timeout) ;
                RpcContext.getContext().setFuture(new FutureAdapter<Object>(future));
                return new RpcResult();
            } else {//同步
                RpcContext.getContext().setFuture(null);
                return (Result) currentClient.request(inv, timeout).get();
            }
        } catch (Exception e) {
           ...
        }
    }
/**
 * Invocation. (API, Prototype, NonThreadSafe)
 * 封裝遠程調用信息(方法名 參數(shù))
 */
public interface Invocation {

    /**
     *方法名
     */
    String getMethodName();

    /**
     *方法參數(shù)類型
     */
    Class<?>[] getParameterTypes();

    /**
     *方法參數(shù)
     */
    Object[] getArguments();

    /**
     *冗余參數(shù)
     */
    Map<String, String> getAttachments();
    
    String getAttachment(String key);
    
   
    String getAttachment(String key, String defaultValue);

    Invoker<?> getInvoker();
}

可以看到doInvoker方法會通過client對象執(zhí)行遠程調用

到此,大家對Protocol層三大對象應該有了一個簡單的了解.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容