有的小伙伴就要问了:这里怎么能是阻塞式的无限等待呢?接口调用不是有超时时间吗?
注意了,这里并不是无限等待。Dubbo 会保证当接口不管是否超时,都会有一个 Runable 的任务被扔到队列里面。所以 take 这里最多也就是等待超时时间这么长时间。
先记着这里,下面会给大家讲到超时检测的逻辑。
看到这里,我们已经和官网上的回答产生一点联系了,我再给大家捋一捋我们现在有的东西:
第一点:用户线程在 AsyncToSyncInvoker 类里面调用了下面这个方法,在等结果。代码和官网上的描述的对应关系如下:
官网上说:会调用不同 DefaultFuture 对象的 get 方法进行等待,这应该是 2.6.x 版本的做法了。
在 2.7.5 版本中是在 AsyncRpcResult 对象的 get 方法中进行等待。而在该方法中,其实是调用了队列的 take 方法,阻塞等待。
在这两个不同对象上的等待是两种完全不同的实现方式。2.7.5 版本里面这样做也是为了做客户端的共享线程池。实现起来优雅了很多,大家可以拿着两个版本的代码自行比较一下,理解到他的设计思路之后觉得真的是妙啊。
但是不论哪个版本,万变不离其宗,请求发出去后,还是需要在用户线程等待。
第二点:发送 request 对象之前构建了一个 DefaultFuture 对象。在这个对象里面维护了一个静态 MAP:
有了调用编号和 DefaultFuture 对象的映射关系。等收到 Response 响应之后,我们从 Response 中取出这个调用编号,就知道这个调用编号对应的是哪个 DefaultFuture 了,妙啊。
但是,等等。“从 Response 中取出这个调用编号”,那不是意外着我们得把调用编号送到服务端去?在哪送的?
答案是在协议里面,还记得上一篇文章中讲协议的时候里面也有个调用编号吗?
呼应上了没有?
每个请求和响应的 header 里面都有一个请求编号,这个编号是一一对应的,这是协议规定好的。
在发送 request 之前,对其进行 encode 的时候写进去的:
org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#encodeRequest
就等着响应了。
接收响应,寻找请求
请求发出去是一件很简单的事情。
但是作为响应回来之后就懵逼。一个响应回来了,找不到是谁发起的它,你说它难受不难受?难受就算了,你就不怕它随便找一个请求就返回了,当场让你懵逼。
你说响应消息是在哪儿处理的?
上篇文章专门讲过哈,说不知道的都是假粉丝:
org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#decodeBody
你看上门代码截图的第 66 行:get request id(获取请求编号)。
从哪里获取?
从 header 中获取。
header 中的请求编号是哪里来的?
发起 request 请求的时候,从 request 对象中取出来写到协议里面的。
request 对象中的请求编号是哪里来的?
通过 AtomicLong 从 0 开始自增来的。
好了,知道这个 id 是怎么来的了,也获取到了。它是在哪里用的呢?
org.apache.dubbo.remoting.exchange.support.DefaultFuture#received(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.exchange.Response, boolean)