19. Dubbo原理解析-通信层之暴露服务

Dubbo的整个远程通信层由exchange,transport, serialize

 

exchange,信息交换层,封装请求响应模式,同步转异步,以Request, Response为中心,扩展接口为Exchanger, ExchangeChannel, HeaderExchangeHandler,ExchangeClient, ExchangeServer

 

transport,网络传输层,抽象mina和netty为统一接口,以Message为中心,扩展接口为Channel, Transporter, Client, Server,Codec

 

serialize,数据序列化层,可复用的一些工具,扩展接口为Serialization, ObjectInput, ObjectOutput,ThreadPool

 

一:提供方暴露服务

1.     服务提供方在DubboProtocol暴露服务export的过程

DubboProtocol构建requestHandler实现了reply方法,用来响应服务调用方的请求,调用具体的服务,并将请求结果封装为RpcResult返回给调用方

requestHandler在创建服务createteServer的 Exchanger bind的时候传入,

Exchangers.bind(url, requestHandler)  //传入url, 处理器,这个处理器会被层层装饰

根据spi策略HeaderExchanger.bind(url,requestHandler)

     构建HeaderExchangeServer对象,new HeaderExchangeServer(Transporters.bind(url,new DecodeHandler(new HeaderExchangeHandler(handler))))

     装饰requestHandler对象

     根据spi策略NettyTransporter.bind(url, channelHandler), 构建NettyServer对象,绑定netty服务启动服务监听

 

2.     NettyServer初始化过程,它是dubbo默认的通讯框架

构造器入参URL统一数据模型包含服务器端地址,超时时间等参数

构造器中装饰传入的ChannelHandler,ChannelHandler其实是一个处理器链,transporter层做了装饰,这里NettyServer构造其中通过ChannelHandlers.wrap方法再次进行装饰

RequestHandleràDecodeHandlerà HeaderExchangeHandlerà MultiMessageHandlerà

HeartbeatHandlerà AllChannelHandler

NettyServer的构造其中会调doOpen方法启动netty。 Netty是基于pipeline管道机制的,我们可以添加阀(org.jboss.netty.channel.ChannelHandler)来实现自己的需求

Decoder: InternalDecoder继承netty对象SimpleChannelUpstreamHandler

Dubbo自定义了一套buffer用来适配底层的nio, 自定的channelBuffer读取netty传递过的字节然后调用dubbo的编码解码器codec.decode解码成Request/Response对象返回

触发netty的messageReceived事件

 

Encoder:InternalEncoder继承于netty的OneToOneEncoder, 将传入的Request/Response/String等对象类型转换成字节流

 

注:为什么Decoder对象没有直接继承于netty的OneToOneDecoder对象能,因为decoder

时候要把字节流读入到dubbo自定义的buffer中,然后再调codec,这样codec的接口就不直接依赖于nio的api,便于codec的扩展及替换

 

3.   NetttyHandler:继承于netty对象SimpleChannelHandler触发netty事件来处理dubbo需求,它会触发一系列的dubbo的ChannelHandler。它是一个处理链AllChannelHandlerà MultiMessageHandlerà HeartbeatHandleràDecodeHandler HeaderExchangeHandler à RequestHandler

 

AllChannelHandler: 默认分发请求实现对于netty事件中除了writeRequested的其他请求chanenlConnected, channelDisconnected,messageReceived, exceptionCaught这四种事件通过构建ChannelEventRunnable任务放入线程池分发

 

MultiMessageHandler:对于消息的received事件,如果消息是批量传输的decode后会由MultiMessage承载,如果是MultiMessage遍历其中的消息分别交由下一个handler处理

 

4.     HeartbeatHandler:处理心跳

       Connected事件设置读写时间戳为当前时间

       Disconnected事件清空读写时间戳

       Sent事件发送请求设置写时间戳为当前时间

       Received事件接收请求设置读时间戳为当前时间

1)  判断消息是心跳请求,当Request对象的mEvent属性为true且mData为null时为心跳事件。

如果此心跳事件需要响应即Request.isTwoway(), 构建心跳响应对象Response,设置响应对象的mEvent=true && mData=null

下面channel处理,最终会通过netty响应客户端。

2)  判断消息是心跳响应,Response的mEvent=true && mData=null, 记录日志直接返回,不在做后续的channel处理了。

3)  如果不是心跳处理,交由下一个处理器处理。

 

5.     DecodeHandler:对于读取的消息或者消息的数据实现了Decodeable接口的decode

 

6.   HeaderExchangeHandler:这里已经到了交换层的handler了,对于这个handler我们主要关心sent事件: 设置channel的写时间戳, 交由后面hanler来发送消息,如果消息是request,根据request获取DefaultFuture设置它的发送时间为当前时间,用来判断是否超时。received事件:接收读取数据

1)  给channel设置读取时间戳

2)  如果是msg是请求类型的Reqeust,

根据request的id构建response对象

调DubboProtocol中构建的requestHandler的replay方法,返回调用结果

跟response对象设置返回结果

Channel.send(response) 向客户端发送响应

3)  如果读取的数据是Response响应并且不是心跳

根据response透传的id获取defaultFuture, 设置defaultFulture的response的值,唤醒线程,defaultFulture的get方法返回调用值

4)  如果是string类型, 处理telnet命令

5)  其他的交由下一个handler处理 //什么场景??

 

下面给出服务提供方服务绑定的活动图

代码交流 2021