Dubbo-聊聊通信模块设计

前言Dubbo源码阅读分享系列文章,欢迎大家关注点赞
SPI实现部分

  1. Dubbo-SPI机制
  2. Dubbo-Adaptive实现原理
  3. Dubbo-Activate实现原理
  4. Dubbo SPI-Wrapper
注册中心
  1. Dubbo-聊聊注册中心的设计
通信模块介绍Dubbo通信模块主要的目的就是解决客户端以服务端通信的问题,核心代码都在dubbo-remoting模块,该模块提供了多种客户端和服务端通信的功能 。Dubbo的通信主要包括是三部分:Exchange、Transport和Serialize,对于序列化部分的设计在单独的模块中,我们再单独聊,这篇文章主要聊Exchange、Transport设计 。对于Dubbo来说没有自己的网络框架,使用现有第三方类库,因此需要设计一套标准API来兼容多种不同的通信框架,dubbo-remoting 模块的结构就是目前Dubbo兼容的所有的通信框架 。在整体模块设计上,dubbo-remoting-api是其他模块上层抽象,其他子模块都是依赖第三方NIO库实现 dubbo-remoting-api模块的 。因此我们想要了解清楚dubbo-remoting设计必须要理解dubbo-remoting-api的设计 。对于dubbo-remoting-api大致可以分为四类,
  1. 核心API设计,主要是包括端口、编码、解码等等核心接口的抽象;
  2. buffer,主要是定义缓冲区相关的接口、抽象类以及实现类;
  3. exchange,抽Request和Response概念抽象以及扩展;
  4. transport,网络传输层的抽象,但它只负责消息的传输;
源码分析核心API设计EndpointEndpoint被翻译端点,这里可以理解为通信中对IP和Port的抽象 , Client和Server端共同的抽象,两个端通过Endpoint建立TCP连接,进行通信 。对于该Endpoint接口定义了三类方法:
  1. get类方法,主要获取Endpoint的本地地址、关联的URL信息以及底层Channel关联的ChannelHandle , 也就是获取建立连接需要的属性;
  2. send方法主要负责发送数据;
  3. close类方法,主要是用来关闭连接;
ChannelChannel可以理解为Client和Server端连接的通道 , 是NIO框架设计中不可缺少的概念 , Channel继承Endpoint,因此拥有Endpoint的能力,对于Channel来说,可以给自身设计一些额外属性 。
ChannelHandlerChannelHandler可以理解为Channel的处理器,ChannelHandler 可以处理Channel的连接建立以及连接断开事件,还可以处理读取到的数据、发送的数据以及捕获到的异常 。
Codec2Codec2实现编码和解码,实现字节与消息体之间的转换 , 类似Netty中编码和解码 。此外,Codec2接口被@SPI 接口修饰了,说明该接口是一个扩展接口,同时encode方法和 decode方法都被@Adaptive注解修饰 , 因此也会生成适配器类,可以根据URL中的codec值确定具体的扩展实现类,这里就体现SPI和URL灵活配置的特性 。
@SPIpublic interface Codec2 {    @Adaptive({Constants.CODEC_KEY})    void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException;    @Adaptive({Constants.CODEC_KEY})    Object decode(Channel channel, ChannelBuffer buffer) throws IOException;    enum DecodeResult {        NEED_MORE_INPUT, SKIP_SOME_INPUT    }}此外还存在DecodeResult的枚举,该枚举是处理粘包和拆包使用的 。
ClientClient继承了Endpoint、Channel等相关的接口,因此对于Client也具备收发消息能力 , Client只可以关联一个 Channel 。
RemotingServerServer与Client不太一样地方就是可以接收多个Client发起的Channel连接,因此RemotingServer接口中存在获取多个Channel列表的接口 。
TransporterTransporter接口是Dubbo在Client和Server上又封装的一层 , 我们可以看到改接口被@SPI以及@Adaptive注解修饰,因此这个是个可扩展的接口 , 默认使用Netty的扩展 , @Adaptive表示可以动态生成该适配的类,根据设置的值确定具体实现的类 。
@SPI("netty")public interface Transporter {    @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})    RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException;    @Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})    Client connect(URL url, ChannelHandler handler) throws RemotingException;}Transporter的实现类有主要有以下几种,每个对应的具体的NIO的实现都在其各自的包中,这样可以通过灵活配置来进行切换不同的实现 。为了验证是否正确,我们简单再来看一下RemotingServer的实现,RemotingServer的实现中,包含每个具体NIO框架的实现,因此这里更加印证Transporter的的抽象 , 让我们可以通过Dubbo SPI修改具体Transporter扩展实现,从而切换到不同的Client和 RemotingServer实现,从而达到NIO库切换,这里我们无需修改任何代码,真正的做到开放-闭合的原则 。

推荐阅读