dubbo整体设计具体可参考官网
服务引用,引用的是一个代理类。invoker通过InvokerInvocationHandler包装,然后通过JavassistProxyFactory#getProxy生成代理类。在调用也会首先经过InvokerInvocationHandler.invoker方法
服务消费端调用流程
1、InvokerInvocationHandler#invoke
org.apache.dubbo.rpc.proxy.InvokerInvocationHandler#invoke
①、这里会把method和args封装成RpcInvocation对象
②、调用invoker.invoke(RpcInvocation)方法
③、recreate()
2、MockClusterInvoker#invoke
org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#invoke
mock的处理:
①、没有mock
②、mock值是以force开头
③、fail-mock
3、AbstractClusterInvoker#invoke
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#invoke
①、通过list从动态服务目录directory过滤出可执行invoker
②、得到负载均衡器RandomLoadBalance 基于权重随机算法
服务提供者URL不存在参数,默认是random
③、调用doInvoke
list从动态服务目录directory过滤出可执行invoker
1、AbstractClusterInvoker#list
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#list
2、AbstractDirectory#list
org.apache.dubbo.rpc.cluster.directory.AbstractDirectory#list
3、RegistryDirectory#doList
org.apache.dubbo.registry.integration.RegistryDirectory#doList
4、route
org.apache.dubbo.rpc.cluster.RouterChain#route
动态服务目录中invokers赋值给finalInvokers,然后通过四种过滤routers进行遍历过滤
①、MockInvokersSelector
org.apache.dubbo.rpc.cluster.router.mock.MockInvokersSelector#route
attachments属性值invocation.need.mock的处理
org.apache.dubbo.rpc.cluster.router.mock.MockInvokersSelector#getNormalInvokers
不是mock协议
②、TagRouter标签路由处理
org.apache.dubbo.rpc.cluster.router.tag.TagRouter#route
③、条件路由
遍历conditionRouters条件路由规则
org.apache.dubbo.rpc.cluster.router.condition.config.ListenableRouter#route
Cluster集群容错doInvoke
集群FailoverClusterInvoker失败自动切换
1、doInvoke
org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke
①、根据随机算法、invocation调用select方法从copyInvokers得到invoker
②、得到的invoker放入invoked集合,表示已经选择过这个
③、选出的invoker设置到Rpc环境上下文中
④、调用选出的invoker的invoker方法
2、select
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#select
①、获取 sticky 配置,sticky 表示粘滞连接。所谓粘滞连接是指让服务消费者尽可能的调用同一个服务提供者,除非该提供者挂了再进行切换
②、如果stickyInvoker有值且可用,就返回这个粘滞连接地址。
③、如果不可用,调用doSelect方法。
④、如果是粘滞连接,且stickyInvoker不可用。也会走doSelect方法,会把得到的invoker赋值给stickyInvoker
2.1、doSelect
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#doSelect
①、如果invokers只有一个,直接返回这个
②、如果有多个会通过loadbalance策略进行选择
③、如果在selected已经选择过的包含了经过loadbalance挑选出来的,会进行重新选择reselect
④、如果重新选择得到的是空,就是获取当前包含在selected的下一个
3、invoke
org.apache.dubbo.rpc.protocol.InvokerWrapper#invoke
4、invoke
org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper.CallbackRegistrationInvoker#invoke
首先调用filterInvoker.invoke方法,得到asyncResult结果后,会回调调用filters过滤链ConsumerContextFilter、FutureFilter、MonitorFilter
5、buildInvokerChain
调用filters的invoke方法,与4中的filterInvoker同属于CallbackRegistrationInvoker的属性值
org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper#buildInvokerChain
调用ConsumerContextFilter的invoke,得到一个异步结果asyncResult
①、ConsumerContextFilter
org.apache.dubbo.rpc.filter.ConsumerContextFilter#invoke
设置RpcContext参数
②、FutureFilter
org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter#invoke
③、MonitorFilter
org.apache.dubbo.monitor.support.MonitorFilter#invoke
设置一些监控信息
6、invoke
org.apache.dubbo.rpc.listener.ListenerInvokerWrapper#invoke
7、invoke
org.apache.dubbo.rpc.protocol.AsyncToSyncInvoker#invoke
AsyncToSyncInvoker完成异步转同步,因为DubboInvoker的执行是异步非阻塞的,所以如果是同步调用,则会在此处阻塞,直到拿到响应结果。
如果invocation指定是同步的,则阻塞等待结果
8、invoke
org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke
9、doInvoke
org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker#doInvoke
①、为RpcInvocation设置path和version
RpcInvocation [methodName=sayHello, parameterTypes=[class java.lang.String], arguments=[world], attachments={path=org.apache.dubbo.demo.DemoService, remote.application=dubbo-demo-consumer-application, interface=org.apache.dubbo.demo.DemoService, version=0.0.0}]
②、获取客户端ExchangeClient,如果客户端数量有多个则会轮训clients
isOneway为true,表示请求不需要拿结果,这里是false,需要拿结果
获取当前方法的所配置的超时时间timeout,默认为1000,1秒
异步去请求,得到一个CompletableFuture
asyncRpcResult表示异步结果。responseFuture会完成后会调用asyncRpcResult中的方法,这里并不会阻塞,如果要达到阻塞的效果在外层使用asyncRpcResult去控制
ExchangeClient客户端发送执行请求数据
1、ReferenceCountExchangeClient
org.apache.dubbo.rpc.protocol.dubbo.ReferenceCountExchangeClient#request(java.lang.Object, int)
2、HeaderExchangeClient
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeClient#request(java.lang.Object, int)
3、HeaderExchangeChannel
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int)
4、AbstractPeer
org.apache.dubbo.remoting.transport.AbstractPeer#send
5、AbstractClient
org.apache.dubbo.remoting.transport.AbstractClient#send
6、NettyChannel
org.apache.dubbo.remoting.transport.netty4.NettyChannel#send
到这里便调用到netty源码部分,进行数据传输
服务消费端读取服务端返回数据
1、channelRead
org.apache.dubbo.remoting.transport.netty4.NettyClientHandler#channelRead
2、AbstractPeer#received
org.apache.dubbo.remoting.transport.AbstractPeer#received
3、MultiMessageHandler#received
org.apache.dubbo.remoting.transport.MultiMessageHandler#received
4、HeartbeatHandler#received
org.apache.dubbo.remoting.exchange.support.header.HeartbeatHandler#received
心跳请求、心跳响应处理,如果不是以上两种会继续往下走
5、AllChannelHandler#received
org.apache.dubbo.remoting.transport.dispatcher.all.AllChannelHandler#received
线程池去处理message
6、ChannelEventRunnable
org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable#run
7、DecodeHandler#received
org.apache.dubbo.remoting.transport.DecodeHandler#received
8、HeaderExchangeHandler#received
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#received
9、HeaderExchangeHandler#handleResponse
HeaderExchangeHandler处理Response时,根据Response的id,可以查到DefaultFuture,然后调用DefaultFuture的complete方法,并设置DefaultFuture的值是Response。当处理请求Request时,会调用ExchangeHandlerAdapter的relpy方法
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleResponse
10、DefaultFuture
DefaultFuture在发送数据中,HeaderExchangeHandler会对当前请求添加一个DefaultFuture,并设置超时时间。最终会调用complete方法把响应传递给AsyncToSyncInvoker
org.apache.dubbo.remoting.exchange.support.DefaultFuture#received(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.exchange.Response)
org.apache.dubbo.remoting.exchange.support.DefaultFuture#received
org.apache.dubbo.remoting.exchange.support.DefaultFuture#doReceived
org.apache.dubbo.rpc.protocol.dubbo.FutureAdapter#FutureAdapter
服务提供端调用流程
服务端提供者接收请求与服务消费者得到响应类似。
首先经过NettyServerHandler,读取请求。最终会经过HeaderExchangeHandler
处理Request数据,首先构造一个Response对象,然后调用ExchangeHandlerAdapter得到一个CompletionStage future,然后给future通过whenComplete绑定一个回调函数,当future执行完了之后,就可以从回调函数中得到ExchangeHandlerAdapter的执行结果,并把执行结果设置给Response对象,通过channel发送出去。
1、ExchangeHandlerAdapter#reply
org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter#reply
转成Invocation对象,可以反射执行方法了。并获取invoker
2、CallbackRegistrationInvoker#invoke
org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper.CallbackRegistrationInvoker#invoke
EchoFilter、ClassLoaderFilter、GenericFilter、ContextFilter、TraceFilter、TimeoutFilter、MonitorFilter、ExceptionFilter
①、EchoFilter#invoke
org.apache.dubbo.rpc.filter.EchoFilter#invoke
判断当前请求是不是一个回升测试,如果是,则不继续执行过滤器链
②、ClassLoaderFilter#invoke
org.apache.dubbo.rpc.filter.ClassLoaderFilter#invoke
设置当前线程的classloader
③、GenericFilter#invoke
org.apache.dubbo.rpc.filter.GenericFilter#invoke
把泛化调用发送过来的信息包装为RpcInvocation对象
④、ContextFilter#invoke
org.apache.dubbo.rpc.filter.ContextFilter#invoke
设置RpcContext.getContext()的参数
⑤、TraceFilter#invoke
org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter#invoke
先执行下一个invoker的invoke方法,调用成功后Trace调用信息
⑥、TimeoutFilter#invoke
org.apache.dubbo.rpc.filter.TimeoutFilter#invoke
只是记录了一下当前时间,当整个filter链都执行完了之后回调TimeoutFilter的onResponse方法时,会判断本次调用是否超时
⑦、MonitorFilter#invoke
org.apache.dubbo.monitor.support.MonitorFilter#invoke
记录服务的执行次数
⑧、ExceptionFilter#invoke
org.apache.dubbo.rpc.filter.ExceptionFilter#invoke
调用时没有做什么,在回调onResponse方法时,会对不同的异常进行处理
3、InvokerWrapper#invoke
org.apache.dubbo.rpc.protocol.InvokerWrapper#invoke
4、DelegateProviderMetaDataInvoker
org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker#invoke
5、invoke
org.apache.dubbo.rpc.proxy.AbstractProxyInvoker#invoke
6、doInvoke
org.apache.dubbo.rpc.proxy.AbstractProxyInvoker#doInvoke
执行的proxy实例的方法。执行到这里便可以执行到服务提供的方法。
为什么要用wrapper,这里不是代理接口,是直接基于某个对象proxy,进行代理
dubbo服务提供者异常在服务消费者抛出
捕获异常,保证结果为正常的AppResponse对象
此时exception不为空,如果是正常返回exception是空的
1、AbstractProxyInvoker#invoke
org.apache.dubbo.rpc.proxy.AbstractProxyInvoker#invoke
2、newDefaultAsyncResult
org.apache.dubbo.rpc.AsyncRpcResult#newDefaultAsyncResult
3、setException
org.apache.dubbo.rpc.AppResponse#setException
4、recreate
org.apache.dubbo.rpc.AppResponse#recreate
服务消费端是在调用AppResponse的recreate方法重新得到一个结果,在recreate方法中会去判断AppResponse对象是否正常,也就是是否存在exception信息,如果存在,则直接throw这个exception。这样就做到了服务提供者异常在消费端抛出
onResponse
消费者端如果不存在这个抛出类
org.apache.dubbo.rpc.filter.ExceptionFilter.ExceptionListener#onResponse
如果是检查异常、签名中出现异常、异常类和接口类位于同一jar文件中、是JDK异常、是dubbo异常则会直接抛出给消费者,如果不是以上几种,则会用RuntimeException进行包裹然后再抛出给消费者。这样处理可以避免消费者端不存在这个抛出类
总结:
Dubbo远程调用逻辑,是在服务导出和服务引用的基础上,其中的核心就是Invokers的调用链,这个Invoker执行链是在服务导出和引用构建的。在服务提供者和消费端请求和响应数据是通过netty或其他服务进行传输的。在这其中也处理了服务提供者异常在消费者抛出和如果消费者不存在异常类问题。当走到这里便可以看懂官网dubbo整体设计。