关键词:
1 Dubbo 整体架构设计
dubbo-remoting 模块提供多种客户端和服务端通信功能。最底层部分即为 Remoting 层:
包括 Exchange、Transport和Serialize 三层。本文主要描述 Exchange 和 Transport 两层。
Dubbo直接集成已有的第三方网络库,如Netty、Mina、Grizzly 等 NIO 框架:
dubbo-remoting-zookeeper使用 Apache Curator 实现与 zk 的交互。
2 dubbo-remoting-api
是其他 dubbo-remoting-*
模块的顶层抽象,其他 dubbo-remoting 子模块都是依赖第三方 NIO 库,来实现 dubbo-remoting-api 模块。
2.1 buffer 包
定义Buffer相关接口、抽象类及实现类。在各 NIO 框架中都有自己的缓冲区实现。但这里的 buffer 包在更高层面,抽象各个 NIO 框架的缓冲区,同时也提供一些基础实现。
2.2 exchange包
抽象 Request、Response,并为其添加很多特性。整个远程调用的核心部分。
2.3 transport包
抽象网络传输层,但只负责抽象单向消息传输,即:
- 请求消息由 Client 端发出,Server 端接收
- 响应消息由 Server 端发出,Client端接收
很多网络库可实现网络传输,如Netty,transport包是在网络库上层的一层抽象。
2 传输层核心接口
“端点(Endpoint)”:一个 ip
和 port
唯一确定,两端点间会创建 TCP
连接,双向传输数据。
Dubbo 将 Endpoint 之间的 TCP 连接抽象为(Channel)通道:
- 发起请求的 Endpoint 抽象为Client
- 接收请求的 Endpoint 抽象为Server
2.1 Endpoint 接口
- getXXX() 用于获得 Endpoint 本身的一些属性,如Endpoint 的本地地址、关联的 URL 信息及底层 Channel 关联的 ChannelHandler
- send() 负责数据发送
- close() 及 startClose() 用于关闭底层 Channel
- isClosed() 方法用于检测底层 Channel 是否已关闭
3 Channel
对 Endpoint 双方连接的抽象,就像传输管道。消息发送端往 Channel 写入消息,接收端从 Channel 读取消息。
3.1 接口定义
继承 Endpoint 接口,也具备开关状态以及发送数据能力。可在 Channel 上附加 KV 属性:
4 ChannelHandler
注册在 Channel 上的消息处理器
4.1 定义
@SPI
注解表明该接口是一个扩展点。
有一类特殊的 ChannelHandler 专门负责实现编解码功能,实现:
- 字节数据与有意义的消息之间的转换
- 或消息之间的相互转换
该接口也是个扩展接口,encode()、decode() 被 @Adaptive 注解修饰,也就会生成适配器类,其中会根据 URL 中的 codec 值确定具体的扩展实现类。
DecodeResult 枚举是在处理 TCP 传输时粘包和拆包使用的,如当前能读取到的数据不足以构成一个消息时,就使用 NEED_MORE_INPUT
。
5 Client、RemotingServer
分别抽象客户端、服务端,都继承 Channel、Resetable 等接口,即都具备读写数据的能力。
都继承了 Endpoint,只是在语义上区分请求和响应职责,都具备发送数据能力。
Client V.S Server
- Client 只能关联一个 Channel
- Server 可接收多个 Client 发起的 Channel 连接,所以在 RemotingServer 接口中定义查询 Channel 的相关方法
6 Transporter
Dubbo 在 Client、Server 之上又封装一层Transporter 接口:
@SPI
注解扩展接口,默认使用“netty”扩展名。
@Adaptive
注解表示动态生成适配器类:
- 先后根据“server”“transporter”的值,确定
RemotingServer
的扩展实现类 - 先后根据“client”“transporter”的值,确定 Client 接口的扩展实现
几乎对每个支持的 NIO 库,都有接口实现:
7.1 为何单独抽象Transporter层,不直接让上层使用 Netty?
利用依赖倒置原则,Netty、Mina、Grizzly 等 NIO 库对外接口和使用方式不同,若在上层直接依赖 Netty 或Grizzly,就依赖具体 NIO 库,而非依赖一个有传输能力的抽象,后续要切换实现,就需修改依赖和接入的相关代码。
而有了 Transporter 层,就可通过 Dubbo SPI,修改使用的具体 Transporter 扩展实现,切换到不同 Client 和 RemotingServer 实现,切换底层 NIO 库,而无须修改代码。当有更先进的 NIO 库出现,也只需开发相应的 dubbo-remoting-*
实现模块提供 Transporter、Client、RemotingServer 等核心接口的实现,即可接入,完全符合开放封闭原则。
7 Transporters
不是一个接口,而是门面类,封装:
- Transporter 对象的创建(通过 Dubbo SPI)
- 及 ChannelHandler 的处理
public class Transporters
private Transporters()
...
public static RemotingServer bind(URL url,
ChannelHandler... handlers) throws RemotingException
ChannelHandler handler;
if (handlers.length == 1)
handler = handlers[0];
else
handler = new ChannelHandlerDispatcher(handlers);
return getTransporter().bind(url, handler);
public static Client connect(URL url, ChannelHandler... handlers)
throws RemotingException
ChannelHandler handler;
if (handlers == null || handlers.length == 0)
handler = new ChannelHandlerAdapter();
else if (handlers.length == 1)
handler = handlers[0];
else // ChannelHandlerDispatcher
handler = new ChannelHandlerDispatcher(handlers);
return getTransporter().connect(url, handler);
public static Transporter getTransporter()
// 自动生成Transporter适配器并加载
return ExtensionLoader.getExtensionLoader(Transporter.class)
.getAdaptiveExtension();
在创建 Client、RemotingServer 时,可指定多个 ChannelHandler 绑定到 Channel,来处理其中传输的数据。Transporters.connect()、bind() 方法都会将多个 ChannelHandler 封装成一个 ChannelHandlerDispatcher 对象。
ChannelHandlerDispatcher 也是 ChannelHandler 接口实现类之一,维护一个 CopyOnWriteArraySet 集,它所有的 ChannelHandler 接口实现都会调用其中每个 ChannelHandler 元素的相应方法。ChannelHandlerDispatcher 还提供增删该 ChannelHandler 集合的相关方法。
8 总结
- Endpoint 接口抽象“端点”概念,这是所有抽象接口的基础
- 上层使用方会通过 Transporters 门面类,获取到 Transporter 的具体扩展实现,然后通过 Transporter 拿到相应 Client、RemotingServer 实现,就能建立(或接收)Channel 与远端进行交互
- 无论 Client、RemotingServer,都会使用 ChannelHandler 处理 Channel 中传输的数据,其中负责编解码的 ChannelHandler 被抽象出为 Codec2 接口。
Transporter 层整体结构图
参考
模块详解(代码片段)
模块的使用一、定义1.什么是模块?模块就是一系列功能的集合体1.内置模块2.第三方模块3.自定义模块模块的格式:1.使用python编写的.py文件2.已被编译成共享库或DLL的C或C++扩展3.把一系列模块组织到一起的文件夹(注:文件夹下... 查看详情
datetime模块详解
1.importdatetime常用方法:ttimedelta()括号里默认为days,进行别的单位运算可以加上如hours=1这样。除了进行减法运算,还可以进行加法运算。>>>a=datetime.datetime.now()-datetime.timedelta(3)>>>adatetime.datetime(2018,4,8,18,11,17,128037 查看详情
random模块详解
random模块的使用random是Python内置模块,想要使用该模块,第一步需要进行导入,下面介绍几种random常用的函数importrandomprint(random.random())#大于0且小于1之间的小数print(random.randint(1,3))#[1,3]大于等于1且小于等于3之间的整数print(random.randra... 查看详情
python的内置模块详解(代码片段)
一、什么是模块 模块就是封装了一些列功能的py文件,我们使用的时候直接导入这个文件,通过传入参数的方式使用其他文件的功能函数二、模块有哪些内置模块自定义模块第三方模块三、如何导入模块 导入模块分为4种... 查看详情
os模块详解
1.importosos.getcwd()当前工作环境的目录路径。>>>importos>>>os.getcwd()‘C:\Users\LENOVO‘os.listdir()返回指定路径下的所有目录。os.remove() 删除一个文件os.removedirs()删除多个目录重点来了,常用的:os.path.isfile()括号里面是... 查看详情
datetime模块详解--基本的日期和时间类型
转自:https://www.cnblogs.com/fclbky/articles/4098204.htmldatetime模块提供了各种类用于操作日期和时间,该模块侧重于高效率的格式化输出在Python中,与时间处理有关的模块包括:time,datetime以及calendardatetime模块定义了两个常量:datetime.MI... 查看详情
python标准库datetime之date模块详解(代码片段)
Python标准库datetime之date模块详解datetime是Python提供的操作日期和时间的标准库,主要有datetime.date模块、datetime.time模块及datetime.datetime模块。其中date模块提供了日期操作相关的方法;time模块提供了时间操作相关的方法;datetime提... 查看详情
python-模块详解(代码片段)
模块:模块的分类:第三方模块/扩展模块:没在安装python解释器的时候安装的那些功能自定义模块:你写的功能如果是一个通用的功能,那你就把它当做一个模块内置模块:安装python解释器的时候跟着装上的那些方法什么是模块:有的功... 查看详情
random模块详解
importrandom#random.random()#随机浮点数,0-1之间#print(random.random())#help(random.random)#random.randint(1,3)#随机整数1-3#print(random.randint(1,3))#print(random.randint(1,3))#print(random.randint(1,3))#random. 查看详情
python基础|文件异常以及模块详解
⭐本专栏旨在对Python的基础语法进行详解,精炼地总结语法中的重点,详解难点,面向零基础及入门的学习者,通过专栏的学习可以熟练掌握python编程,同时为后续的数据分析,机器学习及深度学习的代码能力打下坚实的基础。 查看详情
subprocess模块详解2
1.call()和run功能类似,都是接受一个列表里的参数。>>>importsubprocess>>>a=subprocess.call(["control"]) 2.返回值不为0,程序会报错>>>subprocess.check_call(["control"]) 3.接受一个字符串命令,返回一个元组,第一个... 查看详情
ansible常用模块详解(代码片段)
title:Ansible常用模块详解(3)date:2018-12-0115:22:11tags:Ansiblecategories:Ansiblecopyright:true---Ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署... 查看详情
lora扩频串口通信模块的配置实例详解
模块功能详解组号和地址的概念功能说明每个种功能下都有组号和地址的概念在其中,有了组号的概念,使用方式上就比传统的串口模块更加灵活。如果模块的本地组号和本地地址都设置为0xFF,模块会监听当前信道... 查看详情
详解python模块化——模块(modules)和包(packages)(代码片段)
文章目录引言PythonModules模块导入模块①导入整个模块②导入模块中的特定函数③导入模块中的所有函数给导入的模块一个别名单独运行模块加速模块加载PythonPackages包引用包(Package)中的模块引用包(Package)中... 查看详情
requests模块详解
#第一步:准备请求的相关数据#接口地址url="http://api.lemonban.com/futureloan/member/register"#第二部,准备请求的参数data="mobile_phone":"18189098765","pwd":"lemonban"#第三部添加请求头headers="X-Lemonban-Media-Type":"lemonban.v1"#第四部发 查看详情
python里面的xlrd模块详解(代码片段)
1.什么是xlrd模块?2.为什么使用xlrd模块?3.怎样使用xlrd模块?1.什么是xlrd模块? ?python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库。今天就先来说一下xlrd模块:一、安装xlrd模块 ?到python官网下载h... 查看详情
python——pickle模块的详解(代码片段)
pickle模块详解该pickle模块实现了用于序列化和反序列化Python对象结构的二进制协议。 “Pickling”是将Python对象层次结构转换为字节流的过程, “unpickling”是反向操作,从而将字节流(来自二进制文件或类似... 查看详情
googleplayappbundle使用详解(应用模块化)
GooglePlay上架完整流程系列文章目录【GooglePlay】创建Google开发者账号(注册邮箱账号|创建开发者账号)【GooglePlay】创建并设置应用(访问权限|内容分级|受众群体|类别及联系方式|商品详情)【GooglePlay】AppBundle使用详解(简介|应用内更... 查看详情