Dubbo源码分析-Remoting层
Dubbo源码分析-Remoting层
robin-yao 发表于11个月前
Dubbo源码分析-Remoting层
  • 发表于 11个月前
  • 阅读 645
  • 收藏 34
  • 点赞 1
  • 评论 5

腾讯云 学生专属云服务套餐 10元起购>>>   

Dubbo Github地址 https://github.com/alibaba/dubbo.git

Dubbo Remoting 模块是dubbo底层通信模块的实现。实现对请求/应答的各种逻辑处理,包括同步,异步,心跳等逻辑,最底层的通信借助netty或者mina实现,还有通过jetty servlet暴漏http服务的实现方式。

Remoting Api

公共基础接口类

  • Endpoint

Endpoint 字面意思是端点,端点接口的基本操作有获取端点对应的URL,LocalAddress,及发送关闭Channel的操作;

  • Channel

Channel接口继承Endpoint ,多了对Attribute的操作接口(get,set,remove)及获取连接状态接口,多了获取远端的操作getRemoteAddress方法;

  • ChannelHandler

ChannelHandler 主要包含对Channel的一些处理:
connected(Channel channel);
disconnected(Channel channel);
sent(Channel channel, Object message);
received(Channel channel, Object message);

  • Client

Client继承了Endpoint, Channel, Resetable,并添加reconnect接口

  • Server

Server除了继承Endpoint,还多了下面两个接口:
Collection getChannels() 获取所有的Channel;
Channel getChannel(InetSocketAddress remoteAddress) 根据地址获取特定Channel;

  • Codec

encode,decode 编码解码消息

  • Transporter

Server bind(URL url, ChannelHandler handler) 监听服务端
Client connect(URL url, ChannelHandler handler) 连接到服务端 Transporter 实现类根据采用的底层通信框架的不同,具体封装不同的实现比如netty如图:
输入图片说明

输入图片说明
总结一下这几个基础接口的关系,从Endpoint,Channel,Client,Server的继承关系可以看出,Endpoint作为基础接口包含一些获取端点地址,获取channelHandler,发送消息的接口;
Channel继承Endpoint,Channel可以理解成现实的生活中的水管,它有端点的属性,同时它又有本身的属性;
Client本身是个端点,同时它又可以借助Channel对Server进行连接,它只能对属于它的那个Channel进行操作;
Server本身也是个端点,但它没有继承Channel,因为它是要对多个Channel进行有选择的操作,所以它才有上门列举的那两个操作; Transporter接口明显功能是发起客户端连接或者服务端监听的作用,Transporters的作用主要是通过dubbo采用的SPI思想去根据配置加载Transporter具体实现类,去完成相应的动作;
这里涉及的Client Server Channel都是上层通用对象的抽象,预定义通用属性方法,底层可以灵活的借用不同的框架去实现。大家不要把这些概念和netty mina里的概念混淆。

Buffer包

该包下的类主要是对字节码的操作的封装,ChannelBuffer定义了相应的操作接口,它的实现有Heap实现,和堆外直接内存两张实现;ChannelBuffers实现了对ChannelBuffer操作工具;大概类图如下:
输入图片说明

Transport包

输入图片说明
这里主要是对Client接口的部分实现,AbstractClient实现了Client大部分功能,仅把具体的通信操作留给所依赖的底层通信框架来实现。它实现了连接时锁控制逻辑,重试机制,及加载所要采用的线程池等逻辑。 AbstractServer 里面的逻辑想对简单,仅仅是对一些属性做了些准备,比如从url中解析所要监听的地址,获取线程池,还实现了一个对所有客户端发送消息的send方法。

输入图片说明
上面类图主要展示ChannelHandler的相关实现,ChannelHandler主要是触发Channel进行 CONNECTED,DISCONNECTED,SENT,RECEIVED,CAUGHT这个五个操作,其中WrappedChannelHandler对ChannelHandler做了包装,采用了装饰者模式,直接调用构造函数传入的handler来触发相关操作。这里的Handler设计巧妙,handler里嵌handler,每个handler只需做自己的特殊处理然后交给下一个handler即可,形成了一个处理链,实现功能的分层实现。这里会产生一个疑问,大家这些ChannelHandler都在做自己的业务逻辑处理然后调用handler.xxx(channel),好像谁也没有去触发channel上的动作,这个是在client去做的,其实client本身实现了ChannelHandler接口,比如NettyClient。 上图中的AllChannelHandler ,ExecutionChannelHandler,MessageOnlyChannelHandler,ConnectionOrderedChannelHandler 都是起到分发执行handler动作的类,他们都放在dispatcher包下面,只不过有的是在线程池里去异步执行的具体的handler对channel的操作,有的是直接在本线程中直接执行。

Exchange包

输入图片说明
Exchange这个包下的类主要是提供了可发起远程请求的ExchangeClient,和监听服务端的ExchangeServer。其具体实现分别是HeaderExchangeClient和HeaderExchangeServer。 Exchangers 调用 HeaderExchanger去实现客户端connect,服务端bind动作,分别生成HeaderExchangeClient与HeaderExchangeServer。 输入图片说明

这里Transporters会根据配置的具体Transporter实现类(NettyTransporter,MinaTransporter)来实例化具体的Client,或Server。

输入图片说明

Exchange包层主要是ExchangeClient ExchangerServer ,他们在Transport层上加入了心跳检测,也加入了异步处理逻辑的实现ResponseFuture。其中ResponseFuture 的实现类DefaultFuture,主要是借助ReentrantLock和Condition实现,大家可以看下源码。

Telnet包

输入图片说明
该包下的类主要是实现了一些handler,通过telnet命令行查询状态,log等信息。

Remoting Netty

上面的逻辑把remoting层的功能大概实现了,唯独把依赖底层通信框架的部分抽象给具体的框架实现。Dubbo底层实现有Mina,Netty,Grizzly,还有借助jetty把服务暴漏成http的方式。这里我们只简单的介绍下借助Netty的实现。 这里分别介绍下NettyChannel, NettyClient, NettyServer, NettyHandler, NettyTransporter。

NettyChannel除了继承dubbo本身定义的Channel接口逻辑,这里它把Netty中的Channel概念作为构造参数传入,因为所有的交互最终还是依赖netty中的channel去做。

NettyHandler这里是实现扩展了SimpleChannelHandler,同时把dubbo中定义的handler作为构造参数传入,当触发了netty中的读 写 连接断开等事件时,就会执行各种handler里定义的逻辑。

NettyClient 这里的逻辑比较简单,就是实现AbstractClient中留下的各种doXXX抽象方法,发起远程连接。

NettyServer 通过Netty bootstrap开启服务端监听。

这里把dubbo remoting层涉及到的概念和逻辑基本介绍了。那这里以Netty Remote为例总结一些Client和Server的基本流程。

Client:通过HeaderExchanger调用connect方法 new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler)))); —》NettyTransporter 调用connect方法 new NettyClient(url, listener)。这样一个连接就诞生了。

Server: 通过HeaderExchanger调用bind方法 new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))); —》NettyTransporter 调用bind方法 new NettyServer(url, listener)。这样监听诞生。

框架代码设计小技巧

1 引入使用频率较高第三方类库时,如果类库比较小如fastjson, asm类库为了防止jar冲突,可以直接把源码copy到项目中;

2 在设计抽象类时,比如dubbo的AbstractClient,比如方法的一些公共部分抽离出来,不确定的部分包到抽象方法里,留给子类实现;方法的命名很有技巧 比如 方法open里已知的逻辑我们写直接在抽象类里写,要留给子类的逻辑我们起个抽象方法doOpen。
输入图片说明

https://my.oschina.net/robinyao/blog/804182

下节介绍dubbo rpc层的逻辑。

共有 人打赏支持
粉丝 130
博文 53
码字总数 60598
评论 (5)
chrischeng03
其实只需了解netty3.5就明白了,基本是仿照和抄的
chrischeng03
duubo并不怎么神秘,里层代码就是Proxy加netty抄和hisssion抄
robin-yao

引用来自“chrischeng03”的评论

其实只需了解netty3.5就明白了,基本是仿照和抄的
差不多吧,学习学习里面的代码也是不错的。:smile:
老范的自留地
不错
hahaee
请问你这类关系图怎么弄得? idea里的diagrams没有这么详细的图啊
×
robin-yao
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: