dubbo的请求全过程

前言

前面看完了dubbo的服务发布和引用相关的内容
dubbo的服务发布dubbo的服务引用dubbo的服务调用-集群容错和路由负载
本篇看一下dubbo的一个rpc调用的过程
先看下官网的调用链:在这里插入图片描述

一. 服务发起调用

通过之前的服务引用和发布相关内容,对相关知识已经有部分的了解,当一个已经引用进来的服务,对其发起调用的时候会通过InvokerInvocationHandler代理发起调用:
在这里插入图片描述
通过这个invoker.invoke(rpcInvocation)会来到org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#invoke
在这里插入图片描述
这个方法中有if else判断,这里其实就是对服务调用时的服务降级进行处理,不了解的可以看:dubbo的服务调用-集群容错和路由负载
然后进入:invoker.invoke(invocation)会走到org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#invoke在这里插入图片描述
这里的list(invocation)从directory服务目录和router路由等获取可用的Invoker,然后initLoadBalance(invokers, invocation)动态获取一个负载均衡策略,继续到doInvoke(invocation, invokers, loadbalance)就是带着可用的Invoker和对应的负载均衡策略去执行,不了解的可以看:dubbo的服务调用-集群容错和路由负载,接着进入doInvoke(invocation, invokers, loadbalance)其实是进入集群容错的相关代码,集群容错有多种策略,这里我们已常用的失败重试为例进入查看:org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke
在这里插入图片描述
这个方法中先获取服务配置的重试次数,然后根据重试次数进行for循环,在每次循环中都根据前面获取的可用Invokers和获取的负载均衡loadbalance选择一个可用的Invoker去执行,如果执行成功直接返回,不成功就记录错误并下次循环
这个方法中的select(loadbalance, invocation, copyInvokers, invoked)就是从负载均衡算法中获取一个被选中的Invoker,不了解的还是看:dubbo的服务调用-集群容错和路由负载
继续跟进入invoker.invoke(invocation),进入之后就到了dubbo的扩展点,也就是各种拦截器,很长的一个调用链:

  1. org.apache.dubbo.rpc.protocol.InvokerWrapper#invoke
  2. org.apache.dubbo.rpc.Invoker#invoke
  3. org.apache.dubbo.rpc.filter.ConsumerContextFilter#invoke
  4. org.apache.dubbo.monitor.support.MonitorFilter#invoke
  5. org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter#invoke
  6. org.apache.dubbo.rpc.listener.ListenerInvokerWrapper#invoke
  7. org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke

这一串调用链就是dubbo的扩展点,关于这里可以看官网的文章:扩展点加载,这些扩展点具体都是通过SPI加载的实例,通过扩展点自动包装、扩展点自动装配、扩展点自适应、扩展点自动激活这些方式进行调用链组装,然后我们来到org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke
在这里插入图片描述
进入doInvoke(invocation)会来到org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker#doInvoke
在这里插入图片描述
进入currentClient.request到达org.apache.dubbo.rpc.protocol.dubbo.ReferenceCountExchangeClient#request(java.lang.Object, int, java.util.concurrent.ExecutorService)➡️ org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeClient#request(java.lang.Object, int, java.util.concurrent.ExecutorService)➡️ org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeClient#request(java.lang.Object, int, java.util.concurrent.ExecutorService)➡️ org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int, java.util.concurrent.ExecutorService)
在这里插入图片描述
这里就是创建了一个Requestchannel.send(req),继续跟进下一步走到:org.apache.dubbo.remoting.transport.AbstractPeer#send然后进入netty:org.apache.dubbo.remoting.transport.netty4.NettyChannel#send
在这里插入图片描述
通过channel.writeAndFlush(message)把数据写出去,到这里调用端发起请求就完成了

二. 服务提供端收到调用请求

在调用端通过netty发起请求之后,服务提供端会在org.apache.dubbo.remoting.transport.netty.NettyHandler#messageReceived中收到netty通道中发来的请求消息
在这里插入图片描述
进入 handler.received(channel, e.getMessage())来到:org.apache.dubbo.remoting.transport.AbstractPeer#received➡️ org.apache.dubbo.remoting.transport.MultiMessageHandler#received➡️ org.apache.dubbo.remoting.exchange.support.header.HeartbeatHandler#received➡️
org.apache.dubbo.remoting.transport.dispatcher.all.AllChannelHandler#received
在这里插入图片描述
这个方法进入之后获取一个线程池,把接收的请求交给线程池去处理。所以代码会走到org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable#run
在这里插入图片描述
这里我们是接收调用,所以跟进handler.received(channel, message);调用到org.apache.dubbo.remoting.transport.DecodeHandler#received解码处理
在这里插入图片描述
这个方法对接收的消息进行解码,然后继续调用到org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#received
在这里插入图片描述
由于我们这里是提供方接收请求,所以自然是进入message instanceof Request,然后会走到org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleRequest
在这里插入图片描述
这个方法中先构建了一个Response,然后拿到请求里的数据,然后handler.reply(channel, msg),这一步是异步去执行调用代码,构建了一个CompletableFuture,这个CompletableFuture是jdk8新增的一个异步处理工具,大家可以百度下。然后下面future.whenComplete等待(CompletableFuture.whenComplete表示同一个线程去执行)执行的结果,拿到执行结果后顺着netty通道又把处理结果写回给调用方。这里我们先看下handler.reply(channel, msg),实际调用到了org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter#reply
在这里插入图片描述
这个方法从请求数据中获取到Invoker:getInvoker(channel, inv)
在这里插入图片描述
这里这个exporterMap是不是很熟悉,就是我们之前将服务发布和的时候,最终把发布的服务存到一个map中,就是这个map,这里就是从map中获取一个Exporter并从中提取出来Invoker
然后Result result = invoker.invoke(inv);去执行,然后从这里开始又进入dubbo的扩展点链路:

  1. org.apache.dubbo.rpc.Invoker#invoke
  2. org.apache.dubbo.rpc.filter.EchoFilter#invoke
  3. org.apache.dubbo.rpc.filter.ClassLoaderFilter#invoke
  4. org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter#invoke
  5. org.apache.dubbo.monitor.support.MonitorFilter#invoke
  6. org.apache.dubbo.rpc.filter.TimeoutFilter#invoke
  7. org.apache.dubbo.rpc.filter.ExceptionFilter#invoke
  8. org.apache.dubbo.rpc.protocol.InvokerWrapper#invoke

调用链执行完成后会到达:org.apache.dubbo.rpc.proxy.AbstractProxyInvoker#invoke
在这里插入图片描述
这个方法第一步就是doInvoke,跟进会到达:org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getInvoker在这里插入图片描述
这里就是代理的实际的调用接口,也就是我们自己写的目标接口实现,然后会执行我们自己写的实现逻辑获取结果。
拿到结果后回到org.apache.dubbo.rpc.proxy.AbstractProxyInvoker#invoke,把结果构建成CompletableFuture通知处理完成,就回到了org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleRequest
在这里插入图片描述
这里future.whenComplete会等待获取到结果,然后立即触发到这里,把结果拿到执行channel.send(res),这里就和调用端发送请求数据类似了,会走到:org.apache.dubbo.remoting.transport.AbstractPeer#send➡️ org.apache.dubbo.remoting.transport.netty4.NettyChannel#send
在这里插入图片描述
顺着通道写回数据,到这里服务提供者就完事了,在接收到请求方的请求后作出响应并把结果通过netty告诉给请求方。

三. 请求方接收服务提供方的执行结果

当服务提供方把结果通过netty发回调用方的时候,服务调用方也是在org.apache.dubbo.remoting.transport.netty.NettyHandler#messageReceived里面收到数据,这里和服务提供方收到调用方的请求是类似的
在这里插入图片描述
然后handler.received(channel, e.getMessage())跟进:org.apache.dubbo.remoting.transport.AbstractPeer#send➡️ org.apache.dubbo.remoting.transport.MultiMessageHandler#received➡️ org.apache.dubbo.remoting.exchange.support.header.HeartbeatHandler#received➡️ org.apache.dubbo.remoting.transport.dispatcher.all.AllChannelHandler#received➡️ org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable#run➡️ org.apache.dubbo.remoting.transport.DecodeHandler#received➡️ org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#received
在这里插入图片描述
到这里就和之前的不一样了,之前是请求Request,现在我们接收服务提供者的返回数据,所以是message instanceof Responseorg.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleResponse
在这里插入图片描述
跟进代码会来到:org.apache.dubbo.remoting.exchange.support.DefaultFuture#received(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.exchange.Response, boolean)
在这里插入图片描述
这个方法进来先从org.apache.dubbo.remoting.exchange.support.DefaultFuture#FUTURES中根据请求id删除一个,如果future存在,那么,跟进方法会来到:org.apache.dubbo.remoting.exchange.support.DefaultFuture#doReceived
在这里插入图片描述
这里调用了java.util.concurrent.CompletableFuture#complete通知拿到了结果,这里就是CompletableFuture的用法了。
其实可以理解为在发起请求的时候,创建了一个CompletableFuture,然后等请求结果拿到之后,在通过CompletableFuture的回调,拿到执行的结果。
然后把结果返回到我们实际调用的地方,这样我们就拿到rpc调用的返回结果了… … … . . . …
md 这里是新版本对调用方接收rpc请求返回结果的异步处理,我还没搞懂,等我搞懂了补上TvT

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值