dubbo系列十一、dubbo transport层记录 (4)

在 Dubbo 中会抽象出一个“端点(Endpoint)”的概念,我们可以通过一个 ip 和 port 唯一确定一个端点,两个端点之间会创建 TCP 连接,可以双向传输数据。Dubbo 将 Endpoint 之间的 TCP 连接抽象为通道(Channel),将发起请求的 Endpoint 抽象为客户端(Client),将接收请求的 Endpoint 抽象为服务端(Server)。这些抽象出来的概念,也是整个 dubbo-remoting-api 模块的基础。
Channel 是对两个 Endpoint 连接的抽象,好比连接两个位置的传送带,两个 Endpoint 传输的消息就好比传送带上的货物,消息发送端会往 Channel 写入消息,而接收端会从 Channel 读取消息。

image-20220109234522114

dubbo Channel 我们就可以等同为netty 的Channel ,是个网络通道。那既然有了netty Channel ,为什么还要有个dubbo Channel 呢?由于我们使用dubbo都是使用的netty4,但是dubbo还支持mina、grizzly通信,他们这两种有没有Channel我就不知道了,这样做是为了抽象,做成统一模式,这些通信变化,但是dubbo设计的通信并不会变化。

dubbo Channel 从接口定义来看,具有收发数据能力和附加 KV 属性(即向通道增加一些属性),比如NettyChannel、NettyClient就封装了io.netty.channel.Channel

既然说到这里就得总结dubbo remoting层的重要接口

dubbo remoting层的重要接口

com.alibaba.dubbo.remoting.Endpoint:在 Dubbo 中会抽象出一个“端点(Endpoint)”的概念,我们可以通过一个 ip 和 port 唯一确定一个端点,两个端点之间会创建 TCP 连接,可以双向传输数据。

com.alibaba.dubbo.remoting.Channel:Dubbo 将 Endpoint 之间的 TCP 连接抽象为通道(Channel),Channel有收发消息能力,可以认为等同netty Channel。

com.alibaba.dubbo.remoting.Client:将发起请求的 Endpoint 抽象为客户端(Client)

com.alibaba.dubbo.remoting.Server:将接收请求的 Endpoint 抽象为服务端(Server)

Client、Server分别抽象了客户端和服务端,两者都继承了 Channel、Resetable 等接口,也就是说两者都具备了读写数据能力。Client 和 Server 本身都是 Endpoint,只不过在语义上区分了请求和响应的职责,两者都具备发送的能力,所以都继承了 Endpoint 接口。Client 和 Server 的主要区别是 Client 只能关联一个 Channel,而 Server 可以接收多个 Client 发起的 Channel 连接。所以在 Server 接口中定义了查询 Channel 的相关方法getChannels()/getChannel(InetSocketAddress remoteAddress)

com.alibaba.dubbo.remoting.ChannelHandler:ChannelHandler 是注册在 Channel 上的消息处理器,在 Netty 中也有类似的抽象。有ChannelHandler chain分别承担不同职责,功能灵活强大

com.alibaba.dubbo.remoting.Codec2:编解码的定义,被 @SPI 接口修饰了,表示该接口是一个扩展接口,同时其 encode() 方法和 decode() 方法都被 @Adaptive 注解修饰,也就会生成适配器类,其中会根据 URL 中的 codec 值确定具体的扩展实现类。

com.alibaba.dubbo.remoting.Transporter:Dubbo 在 Client 和 Server 之上又封装了一层Transporter 接口,Transporter 接口上有 @SPI 注解,它是一个扩展接口,默认使用“netty”这个扩展名,@Adaptive 注解的出现表示动态生成适配器类,会先后根据“server”“transporter”的值确定 RemotingServer 的扩展实现类,先后根据“client”“transporter”的值确定 Client 接口的扩展实现。具体有netty、mina、grizzly等不同通信实现。

Transporter 这一层抽象出来的接口,与 Netty 的核心接口是非常相似的。那为什么要单独抽象出 Transporter层,而不是像简易版 RPC 框架那样,直接让上层使用 Netty 呢?

其实这个问题的答案也呼之欲出了,Netty、Mina、Grizzly 这个 NIO 库对外接口和使用方式不一样,如果在上层直接依赖了 Netty 或是 Grizzly,就依赖了具体的 NIO 库实现,而不是依赖一个有传输能力的抽象,后续要切换实现的话,就需要修改依赖和接入的相关代码,非常容易改出 Bug。这也不符合设计模式中的开放-封闭原则。

有了 Transporter 层之后,我们可以通过 Dubbo SPI 修改使用的具体 Transporter 扩展实现,从而切换到不同的 Client 和 RemotingServer 实现,达到底层 NIO 库切换的目的,而且无须修改任何代码。即使有更先进的 NIO 库出现,我们也只需要开发相应的 dubbo-remoting-* 实现模块提供 Transporter、Client、Server 等核心接口的实现,即可接入,完全符合开放-封闭原则。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgjjyz.html