Dubbo源码分析1
这是本人对于Dubbo源码分析的系列一,没有说明Dubbo是什么,不清楚请先了解,此处只是为了给自己做个笔记,也给正在学习Dubbo的同学一些借鉴,后期会继续奉上所有关于Dubbo的逻辑分析,包括Dubbo简介、初始化与请求细节、注册中心、监控中心、治理中心等(由于Dubbo本身的文档已经非常详细了,这里只是重构)。
A.Dubbo初始化、请求处理过程:(此处不涉及非常细节处,均以dubbo协议为例)
一、Dubbo提供者初始化过程分析:
a)Dubbo解析xml,初始化且暴露所有服务
b)由服务配置类ServiceConfig进行初始化工作及服务暴露入口
i.ServiceConfig.export();
c)服务可以多协议暴露
i.ServiceConfig.doExportUrls();
d)在某个协议下暴露服务
i.ServiceConfig.doExportUrlsFor1Protocol();
e)将服务实现类转化成invoker
i.proxyFactory.getInvoker(service,interface,url);
ii.提供者端的invoker封装了服务实现类、URL、Type,状态均是只读,线程安全,是Dubbo中核心模型,Dubbo中的是实体域,其他所有模型都向它靠拢或转化成它,是一个可执行体,通过发起invoke来具体调用服务类,它可能是个本地实现类,也可能是个远程实现类,也可能是个集群实现invoker,由ProxyFactory产生,具体是AbstractProxyInvoker
f)暴露封装服务的Invoker
i.Protocol.export(invoker);
ii.Protocol是Dubbo中的服务域,只在服务启用是加载且无状态,天生线程安全,它是实体域Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理,是Dubbo中远程服务调用层。Dubbo有多种协议支持,有dubbo、http、rmi、hessian、injvm、webService等,下面具体说明服务暴露的细节,包括服务的注册、订阅、暴露、过滤器、监听器的初始化,其中服务的暴露则为Dubbo中的一重点。
g)注册中心协议集成,装饰真正暴露引用服务的协议,增强注册发布功能
i.RegistryProtocol.export(invoker);
ii.ServiceConfig中的protocol是被多层装饰的Protocol,是DubboProtocolRegistryProtocolProtocolListenerWrapperProtocolFilterWrapper(此处是以dubbo协议为例,还有HttpPtotocol、HessianProtocol、RmiProtocol),其中ProtocolFilterWrapper是负责初始化invoker所有的Filter、ProtocolListenerWrapper是负责初始化暴露或引用服务的监听器、RegistryProtocol是负责注册服务到注册中心与向注册中心订阅服务、DubboProtocol是负责服务的具体暴露与引用,且DubboProtocol也负责网络传输层、信息交换层的初始化及底层NIO框架的初始化
h)注册中心协议处理invoker后交给具体协议进行服务暴露
i.RegistryProtocol.doLocalExport(invoker)
ii.RegistryProtocol对原始invoker做一些简单状态后交给具体协议暴露,协议不关系invoker如何生成,由上层传入。接下来就是协议对invoker的暴露,此步骤是Dubbo中的核心。
i)协议层暴露服务前初始化过滤器与服务暴露引用的监听器
i.此步骤由上面提到的ProtocolListenerWrapper、ProtocolFilterWrapper完成,它们是协议的装饰者,增强功能(装饰模式大量使用在Dubbo中)。
j)协议暴露服务
ii.DubboProtocol.export();
iii.进入远程调用层Protocol,此层封装了所有remote层逻辑,对上层透明,暴露服务大致可以分为两步,第一是将invoker转化成Exporter;第二是根据URL绑定IP与端口建立NIO框架的Server;此两步的联系是通过URL关联在一起,协议层缓存了所有暴露的服务,其中key是由group、serviceName、version、port组成,它们的组合具体一个暴露服务,当NIO客户端发起远程调用时,NIO服务端通过此key来决定具体调用执行哪个Exporter,即执行的Invoker,对于NIO框架的底层通信下面会有讲解。
j)协议层创建Exporter后创建NIOServer完成服务的暴露
i.DubboProtocol.openServer(url);
ii.创建封装了Inoker,key的DubboExporter后,通过URL创建NIOServer,且缓存暴露的Exporter,防止重复暴露。另外,同一个JVM中相同协议的服务共享同一个Server,不同服务中只有accept、idleTimeout、threads、heartbeat参数的变化会引用Server中属性的变化,但同JVM中同协议的服务均是引用同一个Server,第一个服务暴露是创建Server,其他服务的暴露是Server最多只是重置个别参数。
k)协议层创建NIOServer,并缓存Server
i.DubboProtocol.createServer(url);
ii.Dubbo底层通信是通过支持异步、事件驱动的NIO网络编程框架,如:Netty、Mina、Grizzly,此框架是典型的Reactor模式使用,使得单个线程处理多个请求,且支持多请求并行执行,NIO接受请求处理流程是读取请求数据解码执行业务逻辑编码发送回应消息,Dubbo是对NIO框架的再次抽象封装,加入一些Dubbo需要的逻辑,通过抽象扩展Handler完成,如HeaderExchangerHandler完成请求-响应模式、同步转异步模式消息发送,AllChannelHandler通过线程池完成请求、响应、连接等并行执行,下面会详细介绍。
iii.Exchangers.bind(url,requestHanler);
iv.Exchangers是门面类,Exchanger的逻辑封装在里面,通过此FACADE调用Exchanger逻辑,Dubbo目前只有一个HeaderExanger实现。从协议层进入Exchanger标志着程序进入了remote层,此层有消息交换层、网络传输层。当协议层调用bind(url,requestHanler)方法并传入最原始的处理Handler时,接下来就是remote层的Server和Hanlder及其他参数初始化的过程。
v.HeaderExchanger.bind(url,requestHandler);
vi.此处是消息交换层与网络传输层初始化的入口,且负责将初始化后的Server传回给协议层。处理流程大致是Dubbo一系列Handler初始化、Server初始化。Handler包装过程是协议层传入的原始requestHandlerHeaderExchangerHandlerDecodeHandlerAllChannelHandlerHeartbeatHandlerMultiMessageHandlerNettyServer[NettyHandler、NettyCodecAdapter]HeaderExchanerServer,HeaderExchanerServer封装了最终的Server,返回给上层协议层,NettyHandler、NettyCodecAdapter是NIO框架的直接处理Handler,NIO框架接受到消息后,先由NettyCodecAdapter解码,再由NettyHandler处理具体业务逻辑,再由NettyCodecAdapter编码后发送,NettyServer是个很重要的类,它既是Server又是Handler,而HeaderExchangerServer只是Server,所有NettyServer参与的Handler的处理过程,MultiMessageHandler是多消息处理Handler、HeartbeatHandler是处理心跳事件的Handler、AllChannelHandler是消息派发器,负责将请求放入线程池,并行执行请求,且Dubbo有多种线程模型、DecodeHandler是编码解码Handler、HeaderExchangerHandler是信息交换Handler,将请求转化成请求-响应模式与同步转异步模式,地位非常重要、requestHandler最后执行的Handler,它会在协议层选择Excporter后选择Invoker,进而执行Filter与invoker,最终执行请求服务实现类方法。
其中NIO框架的通信管道Channel也被Dubbo封装了,Channel直接触发事件并执行Handler,有ChannelNettyChannelHeaderExchangerChannel,通信管道Channel在有客户端连接Server时触发创建并封装成NettyChannel,再由HeaderExchangerHandler创建HeaderExchangerChannel,负责请求-响应模式的处理,注意NettyChannel其实也是个Handler,而HeaderExchangerChannel只是个Channel,是Handler的类说明它也具体Handler特性。
另外,还初始化一些参数,有AllChannelHandler的线程池模型、NettyServer的codesc解码编码方式,timeout超时时间,connectTimeout连接超时时时间,accepts提供者最大接受连接数设置,ildeTimeout时间设置,此处的参数得到都是为了后期可能重置准备。还有消息的序列化与发序列化工作全在NettyCodecAdapter中发起完成。
至此,分析了Dubbo初始化remote层所有初始化流程,还有,对于Transporters也是个门面类,内部调用网络传输层的逻辑,如:NettyTransporter、MinaTransporter。
附上连接过程:(当有客户端连接Server时)
0.NettyHandler.connected()
1.NettyServer.connected()
2.MultiMessageHandler.connected()
3.HeartbeatHandler.connected()
4.AllChannelHandler.connected()
5.DecodeHandler.connected()
6.HaderExchangeHandler.connected()
7.requestHandler.connected()
8.执行服务的onconnect事件的监听方法
下面是Handler、Server、Channel的结构图:
l)将初始化后的Server返回协议层
i.创建好的Server返回,此Server对象很重,缓存
m)协议层将暴露后的Exporter返回给注册中心协议层,最后返回给ServiceConfig进行缓存
i.协议层成功返回Exporter给注册中心协议层,标志着服务暴露完毕,接下来是与注册中心的操作,逻辑上看,注册中心负责服务的注册与发现,所有提供者向注册中心注册服务,并订阅重载配置,所有消费者向注册中心注册服务,并订阅服务,消费者通过注册中心自动发现所有服务提供者,且本地缓存提供者类表,注册中心宕机也不影响消费者调用;程序上看,注册中心也是普通的RPC服务,所有消费者、提供者与注册中心都是长连接。Dubbo目前注册中心服务有MulticastRegistry、ZookeeperRegistry等,关于注册中心的详细介绍待后期奉上。
ii.RegistryProtocol.getRegistry();
iii.得到具体注册中心服务且连接注册中心,此时提供者作为消费者引用注册中心核心服务RegistryService
iv.Registry.register(url);
v.调用远端注册中心的register()方法进行服务注册,且若有消费者订阅此服务,则推送消息让消费者引用此服务,注册中心缓存了所有提供者注册的服务以供消费者发现。
vi.Registry.subscribe(url,listener);
vii.提供者向注册中心订阅所有注册服务的覆盖配置,当注册中心有此服务的覆盖配置注册进来时,推送消息给提供者,让它重新暴露服务,这由管理页面完成。
viii.返回暴露后的Exporter给上层ServiceConfig进行缓存,便于后期撤销暴露。
ix.总结:Exporter的创建、Server的创建、服务的注册与订阅,这些逻辑都是分离的,它们是通过URL联系在一起的。一般情况下,同JVM同协议下的服务共享同一个Server,且消费端的引用这些服务的也可共享一个Client,从而实现多个服务共享同一个通道进行通信,且是基于长连接下,减少了通信的握手次数,高效率通信,另外,远程调用层与信息交换层及网络传输层是Dubbo的核心。
二、Dubbo消费者初始化过程分析:
a)Dubbo解析xml,初始化所有注入的引用服务及init=true引用服务
b)所有dubbo引用服务均由ReferenceConfig入口进行服务的引用
i.ReferenceConfig.get();ReferenceConfig.init();
ii.消费者最终的得到的是服务的代理,在创建代理前初始化所有配置信息,此过程是线程安全的。引用服务的大致过程是由远程调用创建消费者端Invoker,再由ReferenceConfig创建代理返回,此过程的核心是创建消费端的Invoker。在引用服务前,ReferenceConfig先需要判断是否是引用本地服务injvm、是否是点对点直连、是否是通过注册中心连接,判断之后进行最重要的一步:服务的引用。
c)进入远程调用层进行服务的引用
i.Protocol.refer(interface,url);
ii.此方法返回的是个集群invoker,若有多个提供者提供服务,Dubbo将多个服务Invoker伪装成一个集群Invoker,且这个集群Invoker内部的多个invoker,由Directory完成,Directory与List类似,但由不同,当提供者推送消息过来后,Directory可以动态变化,还可以通过Router路由提供者及LoadBalance根据负载均衡算法选中一个提供者,所以当上层进行Invoker调用时,会是:Cluster.invoke()Directory.list()Router.route()LoadBalance.select()invoke.invoke();另外,在invoker转成proxy时,Dubbo对代理也有装饰,如Stub,这个可以实现在真正调用invoker代理前可以做一些事情,类似AOP功能。上面是大致说明以下消费者引用服务的过程,下面详细说明。
d)首先进入注册中心远程调用层RegistryProtocol,且它也经过了ProtocolFilterWrapper、ProtocolListenerWrapper装饰,功能增强
i.RegistryProtocol.refer();
ii.同提供者相同,消费者也首先需要连接注册中心,即引用注册中心这个特殊的RPC服务,并通过注册中心进行服务的订阅与注册。然后判断引用是否是注册中心RegistryService服务,若是绕过注册中心与集群等直接返回刚得到注册中心服务即可,若不是,则说明是普通服务,则需要进入注册中心与集群下面的逻辑。在选择集群策略前,先需要判断引用服务是否需要合并不同实现的返回结果,及是否配置group="*"merger="true"(配置详细说明再说),若配置了,则选择默认的分组聚合集群策略,若没配置,则选择配置的集群策略cluster="failback"或默认策略。下面进入服务引用的重点逻辑分析。
e)服务引用,且向上层返回
i.RegistryProtocol.doRefer(cluster,registry,type,url);
ii.消费端引用服务主要逻辑部分,服务引用大致逻辑是组合url、type创建目录类Directory,此类非常重要,它的功能很复杂,可以看成是NotifyListener服务通知监听器、可以看成Protocol、Registry的聚合类、可以看成一个消费端的List,但它又不同于List,他可以随着注册中心的消息推送而动态变化服务的Invoker数,时刻监听着提供者的变化,典型观察者模式的使用,它封装了所有服务真正引用逻辑、覆盖配置、路由规则等逻辑,初始化时只需要向注册中心发起订阅请求,其他逻辑均是异步的处理,包括服务引用等,且对上层Cluster层是透明的,ResitryProtocol将多个Invoker伪装成一个Invoker返回给上层来转化成代理,上层甚至不知道这是个集群Invoker,在伪装成一个Invoker时,Cluster也被装饰了,增强了Mock功能,这个详细暂不在此处说明。顶层得到伪装后的Invoker,当调用时,会根据初始化时的集群策略、负载均衡策略、路由策略进行选择调用某个Invoker。下面看看Directory的初始化与服务异步引用的分析及集群的处理步骤。
f)目录类Directory初始化、服务订阅、集群伪装
i.在RegistryProtocol中会根据url、type、protocol、registry初始化Directory,Directory功能非常强大,此处暂不说明详细功能。订阅服务前,注册中心首先注册服务,便于后期的监控中心提取数据,通过Directory订阅服务directory.subscribe(url),当有服务提供时,注册中心会推送服务消息给消费者,消费者再进行服务的引用,此处暂不详细说明注册中心的处理逻辑。下面是Directory中的代码块
,接下来服务的引用与变更全部由Directory异步完成,集群策略会将Directory伪装成一个invoker,cluster.join(directory),此代码就是伪装逻辑,Dubbo有很多集群策略,可以配置切换,具体集群逻辑暂不属于这里,后期说明。RegistryProtocol再将伪装后的Invoker返回给上层ReferenceConfig用来创建代理,所以消费者端的对象引用的远程服务其实引用的都是个代理,真正逻辑只有在调用时触发,包括Stub、Proxy、Mock、Cluster、Router、LoadBalance、Filter、Invoker、NIO框架底层通信。
g)Directory服务引用、NIO框架初始化
i.注册中心接收到消费端发送的订阅请求后,会根据提供者注册服务的列表,推送服务消息给消费者,此处的逻辑不同的注册中心实现逻辑不通,详细暂不说明,消费者端接受到注册中心发来的提供者列表后,进行服务的引用,触发Directory监听器的可以是订阅请求、覆盖策略消息、路由策略消息(后两者由管理页面设置),接下面就是服务的引用过程,这逻辑都隐藏在Directory中。
invoker=newInvokerDelegete<T>(protocol.refer(serviceType,url),url,providerUrl);
h)真正进入远程调用层,进行服务的引用与NIO框架的初始化
i.DubboProtocol.refer(type,url);
ii.同服务的暴露逻辑相同,服务的引用步骤也分为两步,一是消费端Invoker的创建,如DubboInvoker,而是NIO框架的Client创建,这两步骤虽然是也是分离的,但它们不是通过URL联系在一起的,而是Invoker聚合了Client,当调用Invoker时,底层实际上是调用Client逻辑进行底层通信。
iii.newDubboInvoker<T>(serviceType,url,getClients(url),invokers);
iv.Invoker创建,可以看出Invoker聚合了Client,此Invoker对象很重,远程调用层进行了缓存invokers.add(invoker);。
v.getClients(url)
vi.此代码负责NIO框架Client创建及初始化,和提供者初始化相似,消费者的初始化也基本上围绕着Client、Handler、Channel对象的创建与不断装饰的过程,不同的是消费者底层是与提供者Server建立连接,此过程在remote层下完成,remote层可分为消息交换层与网路传输层即Exchanger与Transporter层,还有,我们在说提供者初始化时,说过同个JVM中相同协议的服务共享一个Server,同样在消费者初始化时,引用同一个提供者的所有服务可以共享一个Client进行通信,这也就实现了Server-Client在同一个通道中进行通信,实现长连接的高效通信,但是在服务请求数据量比较大时或请求数比较多时,可以设置每服务每连接或每服务多连接可以提高通信效率,具体是通过消费者方connections=2设置连接数。所有消费者端Client有两种,一种是共享型Client,一种是创建型Client,当然共享型Client属于创建型Client一部分,下面具体说说这两种Client创建的细节,也是服务引用的重要细节。
vii.getSharedClient(url)
viii.此为创建共享型Client,共享型Client是指消费者引用同一提供者的服务时,使用同一个Client来提高通信效率,所以对于消费者来说,它连接的每个提供者都需要创建一个创建型Client,其他来自相同提供者的服务引用即可共享此Client,关于创建型Client的创建下面再说。对于共享型Client虽然可以提高通信效率,但会带来一个问题,就是如果所有共享一个Client的服务中的某个服务close了Client会导致其他服务都不能继续通信,这是个安全性问题,Dubbo的解决方案是通过计数的方式来控制这个安全问题,并在共享Client真正关闭后创建一个懒加载的幽灵Client,以备特殊情况使用(此处不说非常细节)。
ix.initClient(url)
x.此为创建创建型Client,也是消费者端服务引用最核心的地方,封装了服务引用中remote层初始化的所有逻辑,与提供者端类似,就是Client、Handler、Channel的创建与不断装饰的过程,在说Client创建细节前,先说说Client类型,与其他产品一样,Dubbo中也有懒加载的概念,即Client分为正常马上连接的Client与懒加载的Client,懒加载的Client是个Client代理,当消费者真正调用服务时,才会去初始化Client、Handler、Channel,也就是才会与Server建立连接。
xi.Client、Handler、Channel初始化
xii.此步骤是服务引用的核心的核心,逻辑完全封装在Protocol远程调用层,对于上层是完全透明的。在进行创建前,Dubbo默认开启remote层的心跳机制与禁止BIO通信,心跳机制是提供者与消费者之间的心跳通信,主要是防止通信异常,如提供者宕机,消费者自动重连提供者。下面重点是服务引用即Client的创建,此过程完成由Directory发起,有关于Directory的细节,后期会专栏介绍此类。同提供者类似,服务引用无非也就是初始化信息交换层与网络传输层即Exchanger与Transporter,且分别由门面类Exchangers与Transporters发起,Transporter返回的Client再经过Exchanger封装装饰后完成初始化并返回给上层Protocol。
详细是:远程调用层Protocol传入原始Handler,后续将是此Handler不断装饰的过程,下面是Handler与Server初始化过程:requestHandlerHeaderExchangerHandlerDecodeHandlerAllChannelHandlerHeartbeatHandlerMultiMessageHandlerNettyClient[NettyHandler、NettyCodecAdapter]HeaderExchanerClient此处remote最终返回包装了NettyClient的HeaderExchangerClient到Protocol层,与提供者相比,消费者有以下异同:
1.初始化的大致逻辑相同
2.提供者暴露服务是绑定IP,而消费者是与提供者建立连接
3.与NettyServer相同,NettyClient也是个Handler
4.与HeaderExchangerServer不同,HeaderExchangerClient也是个Channel,这点一定注意
其中各个Handler、Client与提供者那里基本类似,这里不重复说明它们的功能,对于底层无非就是NIO框架的初始化,与Server建立连接。前面也说过了,返回到protocol层的Client被封装成消费端的Invoker,再返回给重要的Directory,那里动态引用了该服务所有与提供者建立后的Invoker,而真正protocol返回给上层的Invoker是封转了Directory的集群伪装Invoker,当真正调用时,才会根据集群策略、路由策略、负载均衡策略从Directory选择一个Invoker进行调用即Client与Server进行通信,所以Directory在Dubbo占有非常重要的位置,它的功能很复杂。
下面再说说消费者发起的Channel的创建:
消费者的NIO框架初始化是有一步很重要,就是与提供者建立连接即Channel的创建,NIO框架采用的双向通讯的通道Channel,而Dubbo对Channel也做了封装,封装过程是ChannelNettyChannelHeaderExchangerChannel,还有一点非常重要,查看Dubbo源码可知,NettyChannel其实也是个Handler,而HeaderExchangerChannel只是个Channel。在消费者端发起连接时,提供者端与消费者端的NettyHandler将被触发,将执行一系列的Handler或Server逻辑,在NettyHandler触发连接时,执行channelConnected创建Channel,Dubbo对NIO的Channel进行了包装,实现创建NettyChannel,它封装了NIO的Channel与包装Handler的NettyClient,值得注意的所有的事件都由NIO的Channel触发,如:写事件、读事件、连接事件、断开连接事件、出现异常事件。在Handler执行到HeaderExchangerHandler时,创建HeaderExchangerChannel,并且封装从Handler创建并传下来的NettyChannel。其中HeaderExchangerClient构造中有下面这段代码:
HeaderExchangerClient也有个封装了NettyClient的HeaderExchangerChannel,注意这个,因为这是消费者发起请求是底层通信的入口。
下面给出Client与Channel结构图,Handler图上面已有:
总结:所有的初始化,都是为了消费者与提供者之间的通信做准备,下面请结合初始化过程,重点查看通信的过程。再说说,这里的服务引用过程全部隐藏在Directory中,对上层完全透明,只有注册中心触发Directory进而触发服务引用或变更,而上层来说,它接受到的是集群伪装后的Invoker,然后再将Invoker转成Proxy,所以Spring中引用的是一个代理,只有消费者发起调用时,才有一系列的集群、路由、负载均衡逻辑,主要调用逻辑请看下面。
补充:和提供者暴露服务有暴露监听器一样ExporterListener,消费者端有引用服务的监听器InvokerListener,在服务引用时执行。
三、Dubbo消费者--提供者请求过程与响应过程:
a)大致过程
i.消费者发送请求提供者处理消费者接受请求
ii.在提供者与消费者端都初始化完毕时,提供者对外暴露的是Expoter、消费者对外提供的是Proxy,接下来就是从Proxy的执行到Exporter执行的过程,其中Dubbo中的会话域Invocation承载着提供者与消费者端的消息传递,并在每个线程栈中使用。下面是大致处理逻辑:
----------------------------------1.消费者发起请求-------------------------------------------
1.testService.hello();//消费者端呈现层引用的远程服务,这其实就是个代理
2.testServiceSub.hello();//proxy代理被Sub包装了,增强Sub功能,类似AOP
3.testServiceProxy.hello();//消费者端Invoker代理
4.InvokerInvocationHandler.invoker();//由代理类执行的invocationHandler
5.MockClusterInvoker.invoke();//集群对集群Invoker进行的包装,Mock功能
6.ClusterInvoker.invoke();//执行集群伪装的Invoker
7.Directory.list();//查找伪装在集群后面的所有Invoker
8.Router.route();//通过路由规则策略从list中选择一些Invoker
9.LoadBalance.select();//通过负载均衡选策略选中一个Invoker执行
10.Filter.invoke();//执行所有消费者端Filter
11.Invoker.invoke();//执行消费者端的Invoker即DubboInvoker
12.HeaderExchangerClient.request();//信息交换Client执行请求,其中封装了NettyClient、HeaderExchangerChannel
13.HeaderExchangerChannel.request();//此类封装了NettyClient,信息交换通道创建Request执行请求,并创建DefaultFuture返回
14.NettyClient父类AbstractClient.send();//消费者端Client执行请求
15.NettyChannel.send();//Netty通道执行请求发送
16.Channel.write();//NIO框架通知执行写操作,并触发Handler
17.NettyHanlder.writeRequested();//执行NIO框架的顶级Handler
18.NettyCodecAdapter.encode();//执行NIO框架的编码逻辑,以下执行Handler
19.NettyClient父类AbstractPeer.send();//执行装饰了Handler的NettyCient
20.MultiMessageHandler.send();//多消息处理Handler
21.HeartbeatHandler.send();//心跳处理Handler
22.AllChannelHandler.send();//消息派发器Handler
23.DecodeHandler.send();//编码Handler
24.HeaderExchangerHandler.send();//信息交换Handler
25.requestHandler父类ChannelHandlerAdapter.send();//最后执行Handler,以上Handler的执行在消费者端是没有意义,因为Channel.write()执行时,提供者端已经收到消息了,也正在处理了,详细逻辑后面再说,这里为了完整性才这样写(以上是消费者请求大致过程,下面是提供者接受请求后处理并响应消费者过程)。
------------------------------2.提供者处理并响应请求--------------------------------------
26.NettyCodecAdapter.messageReceived();//提供者通过NIO框架通信并接受到消费者发送的信息,当然,这里屏蔽了所有NIO框架的逻辑,也屏蔽了所有编码解码与序列化反序列化的逻辑
27.NettyHandler.messageReceived();//提供者端的NIO顶级Handler处理
28.NettyServer.received();//NIO框架的Server接受请求信息
29.MultiMessageHandler.received();//多消息处理Handler
30.HeartbeatHandler.received();//心跳处理Handler
31.AllChannelHandler.received();//消息派发器Handler
32.DecodeHandler.received();//编码Handler
33.HeaderExchangerHandler.received();//信息交换Handler,请求-响应模式
34.requestHandler.reply();//执行与Exporter交接的最初Handler
35.getInvoker();//先得到提供者端的Exporter再得到相应的提供者端Invoker
36.Filter.invoke();//执行所有提供者端的Filter,所有附加逻辑均由此完成
37.AbstractInvoker.invoke();//执行封装了服务实现类的原始Invoker
38.testServiceImple.hello();//执行服务实现类逻辑
39.NettyChannel.send();//HeaderExchangerHandler得到执行结果Response再返回给消费者,此代码由HeaderExchangerHandler发起
40.Channel.write();//NIO框架通知执行写操作,并触发Handler
41.NettyHanlder.writeRequested();//执行NIO框架的顶级Handler
42.NettyCodecAdapter.encode();//执行NIO框架的编码逻辑,以下执行Handler
43.NettyServer父类AbstractPeer.send();//执行装饰了Handler的NettyServer
44.MultiMessageHandler.send();//多消息处理Handler
45.HeartbeatHandler.send();//心跳处理Handler
46.AllChannelHandler.send();//消息派发器Handler
47.DecodeHandler.send();//编码Handler
48.HeaderExchangerHandler.send();//信息交换Handler
49.requestHandler父类ChannelHandlerAdapter.send();//最后执行Handler,以上Handler的执行在提供者端也是是没有意义,因为Channel.write()执行时,消费者端已经收到响应消息了,也正在处理了,详细逻辑后面再说,这里为了完整性才这样写(以上是消费者请求与提供者接受请求并响应大致过程,下面是消费者接受到提供者响应后处理过程)。
----------------------------------3.消费者接受响应------------------------------------------
50.NettyCodecAdapter.messageReceived();//提供者通过NIO框架通信并接受提供者发送过来的响应
51.NettyHandler.messageReceived();//消费者端的NIO顶级Handler处理
52.NettyClient.received();//NIO框架的Client接受响应信息
53.MultiMessageHandler.received();//多消息处理Handler
54.HeartbeatHandler.received();//心跳处理Handler
55.AllChannelHandler.received();//消息派发器Handler
56.DecodeHandler.received();//编码Handler
57.HeaderExchangerHandler.received();//信息交换Handler,请求-响应模式
58.DefaultFuture.received();//设置response到消费者请求的Future中,以供消费者通过DefaultFuture.get()取得提供者的响应,此为同步转异步重要一步,且请求超时也由DefaultFuture控制。
-----------------------------------4.阻塞或异步断点---------------------------------------
59.Filter.invoke();//消费者异步得到响应后,DubboInvoker继续执行,从而Filter继续执行,从而返回结果给消费者。
60.InvokerInvocationHandler.invoker();//执行invocationHandler后续代码
61.testServiceProxy.hello();//消费者端Invoker代理后续代码
62.testServiceSub.hello();//执行后续代码
63.testService.hello();//执行后续代码
64.呈现结果给消费者客户端
总结:消费者端的DubboInvoker发起请求后,后续的逻辑可以说是异步的或是指定超时时间内阻塞的,直到得到响应结果后,继续执行DubboInvoker中逻辑。对于异步请求时,消费者得到Future,其余逻辑均是异步的。以上主要核心逻辑,对于附加功能,大部分由Filter增强完成。消费者还可以通过设置async、sent、return来调整处理逻辑,async指异步还是同步请求,sent指是否等待请求消息发出即阻塞等待是否成功发出请求、return指是否忽略返回值即但方向通信,一般异步时使用以减少Future对象的创建和管理成本。