dubbo源码解析(11)dubbo的通信方法和invoker

56 篇文章 2 订阅

上一篇我们提及到

DubboInvoker#doInvoker中有这么一段代码

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();
}

这里涉及到dubbo的三种通信模式第二种是有返回值异步通信,配置方式如下

<dubbo:method name="sayHello" async="true" return="true"/>

产生的结果就是立刻返回,但是可以从RpcContext中获取到一个Future,然后从Future中获取到值

第一个if分支是无返回值的异步通信,配置方式是

<dubbo:method name="sayHello" async="true" return="false"/>

产生的结果就是立刻返回,并且RpcContext中无法获取Future

最后一种是同步调用

但实际上dubbo采用的是netty的异步通信方法,这里体现为同步是因为dubbo做了一些处理

 

 currentClient.request(inv, timeout)得到的结果是一个DefaultFuture,原因是在

HeaderExchangerChannel#request中封装了

DefaultFuture future = new DefaultFuture(channel, req, timeout);
try{
    channel.send(req);
}catch (RemotingException e) {
    future.cancel();
    throw e;
}
return future;

进入DefaultFuture的get方法

public Object get(int timeout) throws RemotingException {
    if (timeout <= 0) {
        timeout = Constants.DEFAULT_TIMEOUT;
    }
    if (! isDone()) {
        long start = System.currentTimeMillis();
        lock.lock();
        try {
            while (! isDone()) {
                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();
}

关键在于

while (! isDone()) { done.await(timeout, TimeUnit.MILLISECONDS); if (isDone() || System.currentTimeMillis() - start > timeout) { break; } }

done是一个conditon,熟悉多线程的都知道这会阻碍线程

而isDone方法是

return response != null;

也就是说repsonse为null就会一直阻塞

再看上一节最后的

DefaultFuture.received(channel, response);
future.doReceived(response);
private void doReceived(Response res) {
    lock.lock();
    try {
        response = res;
        if (done != null) {
            done.signal();
        }
    } finally {
        lock.unlock();
    }
    if (callback != null) {
        invokeCallback(callback);
    }
}

done.signal();这句话是关键,这里会唤醒刚刚阻塞的线程。。

这里就解决了异步变同步的问题

还有一个问题,由于socket通信是全双工通信模式,

附一张图说明全半双工

那么问题来了,dubbo是如何保证request和response一一匹配的呢

回到DefaultFuture的构造函数

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);
}

关注最后面两个Map

这里会把Futrure和一个id放在一个map中,

received方法中有一个
DefaultFuture future = FUTURES.remove(response.getId());

从Map中获取这个id得对应的DefaultFutrue并删除。。

异步变同步的方式分析完毕

---------------------------------------------------------------

在前面几篇文章我们分析源码过程中发现有很多invoker

invoker是dubbo最重要的一个组件

public interface Invoker<T> extends Node {

  
    Class<T> getInterface();

   
    Result invoke(Invocation invocation) throws RpcException;

}

这是invoker接口,里面最重要的invoke方法,Invocation是入参 Result是返回值

dubbo中一共有三种类型的invoker

本地执行invoker

    server端:InjvmExporter.getInvoker,通过反射来执行具体方法

远程执行invoker

      client端:DubboInvoker

     server端:AbstractProxyInvoker

多个远程通信伪装中一个invoker

      client端:AbstractClusterInvoker

    server端:AbstractProxyInvoker

 

本节完

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值