Dubbo服务调用的流程
调用某个接口的方法会调用之前生成的代理类,
然后会从 cluster 中经过路由的过滤、负载均衡机制选择一个 invoker 发起远程调用,
此时会记录此请求和请求的 ID 等待服务端的响应。
服务端接受请求之后会通过参数找到之前暴露存储的 map,得到相应的 exporter ,
然后最终调用真正的实现类,再组装好结果返回,这个响应会带上之前请求的 ID。
消费者收到这个响应之后会通过 ID 去找之前记录的请求,
然后找到请求之后将响应塞到对应的 Future 中,唤醒等待的线程,最后消费者得到响应
源码解读
调用链路
FailoverClusterInvoker#doInvoke
–>InvokerWrapper#invoke
–>ProtocolFilterWrapper$CallbackRegistrationInvoker#invoke
–>ProtocolFilterWrapper$1#invoke(ProtocolFilterWrapper#buildInvokerChain构造的invoker)
–>ConsumerContextFilter#invoke
–>FutureFilter#invoke
–>MonitorFilter#invoke
–>ListenerInvokerWrapper#invoke
–>AsyncToSyncInvoker#invoke
–>AbstractInvoker#invoke 判断方法调用是同步还是异步
–>DubboInvoker#doInvoke
–>ReferenceCountExchangeClient#request
–>HeaderExchangeClient#request
–>HeaderExchangeChannel#request
–>AbstractPeer#send
–>AbstractClient#send
–>NettyChannel#send
服务提供者响应调用
HeaderExchangeHandler#received
(1)更新时间戳,心跳处理会根据这个值判断是否超过空闲时间。
(2)request.isEvent()判断是否是事件类型。对于readonly事件,用于Dubbo优雅停机,服务端下线时,因为网络原因,客户端不能及时感知注册中心事件,服务端就会发送readonly报文通知下线。
(3)handleRequest处理Request请求。
(4)handleResponse处理Response响应。
(5)支持Telnet调用。
HeaderExchangeHandler#handleRequest
(1)如果请求参数是Throwable类型, 将异常转成错误信息字符串直接返回。
(2)handler.reply==>DubboProtocol#reply进行方法调用。
(3)远程方法调用完成后,调用channel.send发送Response响应。
DubboProtocol#requestHandler
查找服务提供方invoker实例,并进行服务的真实调用。
获取服务暴露的端口和调用传递的接口,根据端口、接口名、接口分组和版本构造唯一的key,从HashMap中取出对应的Exporter并调用Invoker属性值(在服务暴露时,提供的服务会根据端口、接口名、接口版本和接口分组把实例Invoker存储到HashMap中,客户端调用时需要带有相同信息构造的key)。
AbstractProxyInvoker#invoke
AbstractProxyInvoker有2个匿名内部实现类,分别是JavassistProxyFactory和JdkProxyFactory。调用代理类的doInvoke方法,去调用真正的服务方法,获取到返回值后,封装成AsyncRpcResult 。
心跳检测
HeartbeatTimerTask#doTask
ReconnectTask#doTask
如果客户端断开连接,会重新连接;客户端空闲超时也会触发重连。