五 捋代碼--dubbo源碼調(diào)用之消費(fèi)端

有了前兩章服務(wù)發(fā)布和服務(wù)引用的模型基礎(chǔ),調(diào)用將會(huì)把兩部分串聯(lián)起來(lái)。先來(lái)回顧下引用的模型(因?yàn)槿肟谠谶@里)


dubbo引用模型

然后我們先來(lái)看章大圖,有個(gè)總體調(diào)用印象,下面將會(huì)一一講解


dubbo調(diào)用時(shí)許圖

我們已經(jīng)知道,消費(fèi)端引用的實(shí)際對(duì)象是生成的對(duì)接口的代理對(duì)象,所以最后進(jìn)入InvokerInrocationHandler中

public class InvokerInvocationHandler implements InvocationHandler {

    private final Invoker<?> invoker;

    public InvokerInvocationHandler(Invoker<?> handler) {
        this.invoker = handler;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        .....
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }

}

引用模型發(fā)現(xiàn)此時(shí)invoker對(duì)象為MockClusterInvoker,顯然這是一層mock配置的包裝,看一下代碼

 public Result invoke(Invocation invocation) throws RpcException {
        Result result = null;

        String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
        if (value.length() == 0 || value.equalsIgnoreCase("false")) {
            //no mock
            result = this.invoker.invoke(invocation);
        } else if (value.startsWith("force")) {
            if (logger.isWarnEnabled()) {
                logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
            }
            //force:direct mock
            result = doMockInvoke(invocation, null);
        } else {
            //fail-mock
            try {
                result = this.invoker.invoke(invocation);
            } catch (RpcException e) {
                if (e.isBiz()) {
                    throw e;
                } else {
                    if (logger.isWarnEnabled()) {
                        logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
                    }
                    result = doMockInvoke(invocation, e);
                }
            }
        }
        return result;
    }

的確是,在配置為force強(qiáng)制走mock或非業(yè)務(wù)異常時(shí)都會(huì)調(diào)用mock邏輯,此處不影響主流程,我們跳過(guò),有機(jī)會(huì)單聊聊容錯(cuò)機(jī)制。主流程調(diào)用下一鏈invoker--->FailoverClusterInvoker的invoke方法,此方法在其爸爸抽象類AbstractClusterInvoker中

    public Result invoke(final Invocation invocation) throws RpcException {

        //檢查invoke狀態(tài)
        checkWhetherDestroyed();
        //負(fù)載算法載體
        LoadBalance loadbalance;
        //從目錄類中找出此請(qǐng)求對(duì)應(yīng)的所有invoker
        List<Invoker<T>> invokers = list(invocation);
        if (invokers != null && invokers.size() > 0) {
            //根據(jù)擴(kuò)展點(diǎn)機(jī)制獲取負(fù)載策略
            loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
                    .getMethodParameter(invocation.getMethodName(), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
        } else {
            loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);
        }
        //如果是異步操作添加相關(guān)標(biāo)志
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
        //模版方式調(diào)用子類方法
        return doInvoke(invocation, invokers, loadbalance);
    }

通過(guò)這段代碼,我們可以看到重點(diǎn)是生成了一個(gè)LoadBalance實(shí)體,然后調(diào)用各clusterInvoker子類實(shí)現(xiàn)的doInvoke方法,下面先分析下調(diào)用核心LoadBalance,先看下擴(kuò)展獲取到的適配類

ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
                    .getMethodParameter(invocation.getMethodName(), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE))

顯然默認(rèn)配置擴(kuò)展點(diǎn)為DEFAULT_LOADBALANCE=random,看下配置文件

//隨機(jī),按權(quán)重設(shè)置隨機(jī)概率
random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
//輪循,按公約后的權(quán)重設(shè)置輪循比率
roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
//最少活躍數(shù)
leastactive=com.alibaba.dubbo.rpc.cluster.loadbalance
//一致型哈希算法
consistenthash=com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance

dubbo一共實(shí)現(xiàn)了四種常見(jiàn)的分布負(fù)載算法,我們這里簡(jiǎn)單分析一下常用RandomLoadBalance實(shí)現(xiàn)原理,其他三種算法有機(jī)會(huì)單獨(dú)細(xì)細(xì)分享

  • RandomLoadBalance:隨機(jī),按權(quán)重設(shè)置隨機(jī)概率
      int length = invokers.size(); // 總個(gè)數(shù)
        int totalWeight = 0; // 總權(quán)重
        boolean sameWeight = true; // 權(quán)重是否都一樣
        for (int i = 0; i < length; i++) {
            int weight = getWeight(invokers.get(i), invocation);
            totalWeight += weight; // 累計(jì)總權(quán)重
            if (sameWeight && i > 0
                    && weight != getWeight(invokers.get(i - 1), invocation)) {
                sameWeight = false; // 計(jì)算所有權(quán)重是否一樣
            }
        }
        if (totalWeight > 0 && !sameWeight) {
            // 如果權(quán)重不相同且權(quán)重大于0則按總權(quán)重?cái)?shù)隨機(jī)
            int offset = random.nextInt(totalWeight);
            // 并確定隨機(jī)值落在哪個(gè)片斷上
            for (int i = 0; i < length; i++) {
                offset -= getWeight(invokers.get(i), invocation);
                if (offset < 0) {
                    return invokers.get(i);
                }
            }
        }
        // 如果權(quán)重相同或權(quán)重為0則均等隨機(jī)
        return invokers.get(random.nextInt(length));

此時(shí)的invokers中的服務(wù)的順序有6種情況,分別為ABC,BAC,ACB,CAB,BCA,CBA 此時(shí)的 totalWeight=1+2+3=6,此時(shí)offset=random.nextInt(totalWeight)=random.nextInt(6)=【0,1,2,3,4,5】
可以通過(guò)一個(gè)列表描述碰撞到A,B,C的情況:

隨機(jī)數(shù) offset offset offset offset offset offset
invoker排序 0 1 2 3 4 5
ABC A B B C C C
BAC B B A C C C
ACB A C C C B B
CAB C C C A B B
BCA B B C C C A
CBA C C C B B A

當(dāng)ABC以不同順序排列時(shí),offset按0到5到順序時(shí)概率保持1/6,1/3和1/2,在看下代碼實(shí)現(xiàn)中offset到值
如果offset=0的時(shí)候,如果invokers=ABC 則調(diào)用的是A,因?yàn)?-1<0 ;
offset=1的時(shí)候,會(huì)經(jīng)過(guò)幾個(gè)循環(huán)
1、offset=1-1=0,此時(shí)offset=0,繼續(xù)下一步
2、offset=0-1=-1>0,此時(shí)調(diào)用B
offset=3的時(shí)候,會(huì)經(jīng)過(guò)幾個(gè)循環(huán)
1、offset=3-1=2,此時(shí)offset=2,繼續(xù)下一步
2、offset=2-2=0,繼續(xù)下一步
3、offset=0-3=-3, 此時(shí)調(diào)用C
以此類推,每次減去ABC到權(quán)重值,offset重新賦值為與其趨緊值

  • RoundRobinLoadBalance 權(quán)重輪訓(xùn)調(diào)度算法:
    1.根據(jù)服務(wù)器的不同處理能力,給每個(gè)服務(wù)器分配不同的權(quán)值,使其能夠接受相應(yīng)權(quán)值數(shù)的服務(wù)請(qǐng)求。

  • LeastActiveLoadBalance最少活躍數(shù)
    1、最少活躍調(diào)用數(shù),相同活躍數(shù)的隨機(jī),活躍數(shù)指調(diào)用前后計(jì)數(shù)差;
    2、使慢的提供者收到更少請(qǐng)求,因?yàn)樵铰奶峁┱叩恼{(diào)用前后計(jì)數(shù)差會(huì)越大。

  • ConsistentHashLoadBalance 一致性hash算法:
    1.一致性 Hash,相同參數(shù)的請(qǐng)求總是發(fā)到同一提供者。
    2.當(dāng)某一臺(tái)提供者掛時(shí),原本發(fā)往該提供者的請(qǐng)求,基于虛擬節(jié)點(diǎn),平攤到其它提供者,不會(huì)引起劇烈變動(dòng)。

回歸主題,根據(jù)模型圖繼續(xù)調(diào)用進(jìn)入FailoverClusterInvoker的doInvoke方法,

  public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
            .....
          
 for (int i = 0; i < len; i++) {
            if (i > 0) {
                checkWhetherDestroyed();
                copyinvokers = list(invocation);
                //重新檢查一下
                checkInvokers(copyinvokers, invocation);
            }
          //loadbance算法選擇,invoked用來(lái)提出已經(jīng)選擇過(guò)的invoker
            Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);
            invoked.add(invoker);
            RpcContext.getContext().setInvokers((List) invoked);
           .....
              進(jìn)行向下調(diào)用
                Result result = invoker.invoke(invocation);
            .....
               
    }
}

發(fā)現(xiàn)FailoverClusterInvoker有個(gè)for循環(huán)進(jìn)行輪詢,當(dāng)異常時(shí)會(huì)重試其他服務(wù)器。
根據(jù)模型繼續(xù)向下,此時(shí)的invoker為RegistryDirectory$InvokerDelegete,外邊還有層層的filters,此處跳過(guò),InvokerDelegete中包裝的就是我們的DubboInvoker,進(jìn)入其doInvoker方法

 protected Result doInvoke(final Invocation invocation) throws Throwable {
        RpcInvocation inv = (RpcInvocation) invocation;
        //獲取調(diào)用方法名
        final String methodName = RpcUtils.getMethodName(invocation);
        inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
        inv.setAttachment(Constants.VERSION_KEY, version);

        //獲取通訓(xùn)客戶端
        ExchangeClient currentClient;
        if (clients.length == 1) {
            currentClient = clients[0];
        } else {
            currentClient = clients[index.getAndIncrement() % clients.length];
        }
        try {
            //異步調(diào)用,通過(guò)回調(diào)通知方式
            boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
            //只發(fā)送消息,不管返回結(jié)果直接結(jié)束方式
            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 {
                //普通調(diào)用
                RpcContext.getContext().setFuture(null);
                return (Result) currentClient.request(inv, timeout).get();
            }
        } catch (TimeoutException e) {
            throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        } catch (RemotingException e) {
            throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

這時(shí)獲取到了通訊的客戶端,并且dubbo除了同步返回結(jié)果,還支持兩種調(diào)用方式

  • oneway 當(dāng)方法或接口有此注解,則只發(fā)送消息,用在void方法上
  • isAsync異步處理結(jié)果的方式

我主要分析正常同步調(diào)用

         return (Result) currentClient.request(inv, timeout).get();

currentClient是我們上一章獲取到到客戶端,從引用模型圖中可以看出這client是ReferenceCountExchangeChient,這只是只是個(gè)包裝類,進(jìn)入內(nèi)部HeaderExchangeClient,然后是進(jìn)入成員屬性HeaderExchangeChannel中

  public ResponseFuture request(Object request, int timeout) throws RemotingException {
        if (closed) {
            throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
        }
        // create request.
        Request req = new Request();
        req.setVersion("2.0.0");
        //設(shè)置通道屬性為雙向
        req.setTwoWay(true);
        req.setData(request);
        DefaultFuture future = new DefaultFuture(channel, req, timeout);
        try {
            channel.send(req);
        } catch (RemotingException e) {
            future.cancel();
            throw e;
        }
        return future;
    }

此處包裝了兩個(gè)重要的模型Request和DefaultFuture用做請(qǐng)求數(shù)據(jù)和返回?cái)?shù)據(jù)的載體,其中DefaultFuture下面返回時(shí)還會(huì)介紹。
先看channel.send方法,這時(shí)channel就是我們的NettyClient了,根據(jù)上一章的內(nèi)容,我們知道最終會(huì)從NettyChannel緩存中得到一個(gè)NettyChannel,然后調(diào)用NettyChannel的send方法


    public void send(Object message, boolean sent) throws RemotingException {
        super.send(message, sent);

        boolean success = true;
        int timeout = 0;
        try {
            ChannelFuture future = channel.write(message);
            if (sent) {
                timeout = getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
                success = future.await(timeout);
            }
            Throwable cause = future.getCause();
            if (cause != null) {
                throw cause;
            }
        } catch (Throwable e) {
            throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e);
        }

        if (!success) {
            throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress()
                    + "in timeout(" + timeout + "ms) limit");
        }
    }

這就沒(méi)什么說(shuō)的了,標(biāo)準(zhǔn)的netty通訊發(fā)送消息的寫法。
發(fā)送完消息,回到我們的HeaderExchangeChannelrequest方法中

 public ResponseFuture request(Object request, int timeout) throws RemotingException {
        if (closed) {
            throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
        }
        // create request.
        Request req = new Request();
        req.setVersion("2.0.0");
        req.setTwoWay(true);
        req.setData(request);
        DefaultFuture future = new DefaultFuture(channel, req, timeout);
        try {
            channel.send(req);
        } catch (RemotingException e) {
            future.cancel();
            throw e;
        }
        return future;
    }

此方法返回的是剛才的生成的DefaultFuture類。層層返回,就回到了我們最初的DubboInvoker類的doInvoke方法中

  return (Result) currentClient.request(inv, timeout).get();

因此currentClient.request(inv, timeout)返回的是一個(gè)DefaultFuture實(shí)體,然后調(diào)用其get()方法,獲取返回結(jié)果。
這里先讓大家想象一下,Netty是異步通信框架,發(fā)送和接受是兩個(gè)線程,那dubbo是怎么接受到返回結(jié)果的呢?
哈哈,不知道大家想到?jīng)],常用的做法就是通過(guò)并發(fā)編程線程通信的方式,來(lái)做兩個(gè)線程間的雙向通信綁定

   public Object get() throws RemotingException {
        return get(timeout);
    }

    public Object get(int timeout) throws RemotingException {
        if (timeout <= 0) {
            timeout = Constants.DEFAULT_TIMEOUT;
        }
        if (!isDone()) {
            long start = System.currentTimeMillis();
            lock.lock();
            try {
                //判斷是否返回了結(jié)果
                while (!isDone()) {
                    //阻塞當(dāng)前線程,等待返回結(jié)果,喚醒線程
                    done.await(timeout, TimeUnit.MILLISECONDS);
                    if (isDone() || System.currentTimeMillis() - start > timeout) {
                        break;
                    }
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
            if (!isDone()) {
                throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
            }
        }
        return returnFromResponse();
    }

簡(jiǎn)單的并發(fā)編程操作,通過(guò)get方法,請(qǐng)求線程進(jìn)行了阻塞。然后我們?cè)趤?lái)想象一下線程通信控制時(shí),必須兩個(gè)線程持有同一個(gè)對(duì)象,那接收線程怎么找到這個(gè)引用這個(gè)對(duì)象的呢?
回顧下我們的應(yīng)用模型圖,NettyClient中作為信息接受體的是NettyClientHandler類,根據(jù)netty操作,我們知道接受信息進(jìn)入channelRead方法

   public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
        try {
            handler.received(channel, msg);
        } finally {
            NettyChannel.removeChannelIfDisconnected(ctx.channel());
        }
    }

然后我們看到了handler.received(channel, msg)方法,我們根據(jù)模型圖層層遞進(jìn),進(jìn)入到AllChannelHandler方法中

 public void received(Channel channel, Object message) throws RemotingException {
        ExecutorService cexecutor = getExecutorService();
        try {
            cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
        } catch (Throwable t) {
            //TODO 臨時(shí)解決線程池滿后異常信息無(wú)法發(fā)送到對(duì)端的問(wèn)題。待重構(gòu)
            //fix 線程池滿了拒絕調(diào)用不返回,導(dǎo)致消費(fèi)者一直等待超時(shí)
            if(message instanceof Request && t instanceof RejectedExecutionException){
                Request request = (Request)message;
                if(request.isTwoWay()){
                    String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
                    Response response = new Response(request.getId(), request.getVersion());
                    response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
                    response.setErrorMessage(msg);
                    channel.send(response);
                    return;
                }
            }
            throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
        }
    }

看到這里起了個(gè)異步線程cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message))進(jìn)行處理返回值

 public void run() {
        switch (state) {
            case CONNECTED:
                try {
                    handler.connected(channel);
                } catch (Exception e) {
                    logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
                }
                break;
            case DISCONNECTED:
                try {
                    handler.disconnected(channel);
                } catch (Exception e) {
                    logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
                }
                break;
            case SENT:
                try {
                    handler.sent(channel, message);
                } catch (Exception e) {
                    logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
                            + ", message is " + message, e);
                }
                break;
            case RECEIVED:
                try {
                    handler.received(channel, message);
                } catch (Exception e) {
                    logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
                            + ", message is " + message, e);
                }
                break;
            case CAUGHT:
                try {
                    handler.caught(channel, exception);
                } catch (Exception e) {
                    logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
                            + ", message is: " + message + ", exception is " + exception, e);
                }
                break;
            default:
                logger.warn("unknown state: " + state + ", message is " + message);
        }
    }

看到RECEIVED分支下調(diào)用了傳進(jìn)來(lái)到 handler.received(channel, message)方法,那么你猜下這個(gè)handler是誰(shuí)呢?對(duì)了正是DecodeHandler,根據(jù)上一章只是我們知道,引用服務(wù)時(shí),有一段 new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);來(lái)生成包裝后的client,此時(shí)new DecodeHandler(new HeaderExchangeHandler(handler))這個(gè)就被賦值到了AllChannelHandler中,根據(jù)模型圖我們也可以看到這點(diǎn)。DecodeHandler是用來(lái)網(wǎng)絡(luò)通信編碼的,直接進(jìn)入HeaderExchangeHandler方法

  public void received(Channel channel, Object message) throws RemotingException {
        channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
        ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
        try {
            if (message instanceof Request) {
                // handle request.
                Request request = (Request) message;
                if (request.isEvent()) {
                    handlerEvent(channel, request);
                } else {
                    if (request.isTwoWay()) {
                        Response response = handleRequest(exchangeChannel, request);
                        channel.send(response);
                    } else {
                        handler.received(exchangeChannel, request.getData());
                    }
                }
            } else if (message instanceof Response) {
                //處理返回結(jié)果
                handleResponse(channel, (Response) message);
            } else if (message instanceof String) {
                if (isClientSide(channel)) {
                    Exception e = new Exception("Dubbo client can not supported string message: " + message + " in channel: " + channel + ", url: " + channel.getUrl());
                    logger.error(e.getMessage(), e);
                } else {
                    String echo = handler.telnet(channel, (String) message);
                    if (echo != null && echo.length() > 0) {
                        channel.send(echo);
                    }
                }
            } else {
                handler.received(exchangeChannel, message);
            }
        } finally {
            HeaderExchangeChannel.removeChannelIfDisconnected(channel);
        }
    }

然后順藤摸瓜,進(jìn)入 handleResponse(channel, (Response) message)方法

  static void handleResponse(Channel channel, Response response) throws RemotingException {
        if (response != null && !response.isHeartbeat()) {
            DefaultFuture.received(channel, response);
        }
    }

看,我們又回到了DefaultFuture類中!

    public static void received(Channel channel, Response response) {
        try {
            //根據(jù)id找到原有請(qǐng)求線程
            DefaultFuture future = FUTURES.remove(response.getId());
            if (future != null) {
                future.doReceived(response);
            } else {
                logger.warn("The timeout response finally returned at "
                        + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))
                        + ", response " + response
                        + (channel == null ? "" : ", channel: " + channel.getLocalAddress()
                        + " -> " + channel.getRemoteAddress()));
            }
        } finally {
            CHANNELS.remove(response.getId());
        }
    }

在DefaultFuture的方法中我們找到 DefaultFuture future = FUTURES.remove(response.getId())這句話,原來(lái)response中有個(gè)id用來(lái)連接兩個(gè)線程啊!我們回頭找下

    public DefaultFuture(Channel channel, Request request, int timeout) {
        this.channel = channel;
        this.request = request;
        this.id = request.getId();
        this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
        // put into waiting map.
        FUTURES.put(id, this);
        CHANNELS.put(id, channel);
    }

原來(lái)在DefaultFuture構(gòu)造方法里就已經(jīng)緩存了這個(gè)id和示例的對(duì)應(yīng)關(guān)系,后邊就不用說(shuō)了,調(diào)用DefaultFuture的doReceived肯定解鎖,獲取返回結(jié)果了

    private void doReceived(Response res) {
        lock.lock();
        try {
            response = res;
            if (done != null) {
              //解鎖,原有g(shù)et方法激活
                done.signal();
            }
        } finally {
            lock.unlock();
        }
        if (callback != null) {
            invokeCallback(callback);
        }
    }

此時(shí) get()接到通知就可以舒舒服服去拿到返回結(jié)果,給調(diào)用方了。

到此,調(diào)用過(guò)程我們已經(jīng)分析完上半部分了------客戶端發(fā)送和接收返回結(jié)果。
下章我們介紹服務(wù)端接收請(qǐng)求,處理請(qǐng)求,返回結(jié)果。

下一篇 ??? dubbo調(diào)用源碼之服務(wù)端
首頁(yè) ??? dubbo源碼欣賞簡(jiǎn)介

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

推薦閱讀更多精彩內(nèi)容