Dubbo篇:基于Netty实现Dubbo协议编解码源码分析



Dubbo协议解析


         Dubbo协议设计参考了TCP/IP协议,包括协议头和协议体两部分。16字节报文头主要携带了魔法数(0xdabb,用于分割两个不同请求),以及当前请求报文是否是Request、Response、心跳和事件的信息,请求时也会携带当前报文体内序列化协议编号,另外还有请求状态、请求唯一表示和报文体长度。

在这里插入图片描述

         0~7           魔数高位   存储0xda
         8~15         魔数低位   存储0xbb
         16             数据包类型   是否为双向的RPC调用(比如方法调用有返回值),0位Response,1位Request
         17             调用方式    16位为1的情况下有效,0为单向调用,1为双向调用
         18             事件标识     0为请求/响应包,1位心跳包
         19~23       序列化器编号
         24~31       状态
         32~95       请求编码     8个字节存储RPC请求的唯一id,用来将请求和响应做关联
         96~127     消息体长度     4个字节消息体,存有Dubbo版本号、服务接口名、服务接口版本、方法名、参数类型、方法参数值和请求额外参数



Netty编解码器扩展



         Netty提供了两个基类,一个是ByteToMessageDecoder解码基类,一个是MessageToByteEncode编码基类,用于自定义协议扩展。


ByteToMessageDecoder



         ByteToMessageDecoder是一个抽象类,解码方法名decode,需要子类去实现。继承关系如下图:

在这里插入图片描述

         ByteToMessageDecoder继承了ChannelInboundHandlerAdapter,是一个Inbound入站处理器,关于ChannelPipeline事件传播机制前面几篇文章已经做了详细介绍,此处不再赘述,所以重点关注一下其channelRead方法,即读事件的传播,代码如下:

在这里插入图片描述

         其实现比较简单,主要是对ByteBuf解码,然后继续向下传播ChannelRead事件,解码具体实现在callDecode方法中,代码实现如下:


在这里插入图片描述

         callDecode中会读取数据,然后会调用decodeRemovalReentryProtection继续解码,在decodeRemovalReentryProtection中我们看到了所期待的的调用子类的decode方法解码。


MessageToByteEncoder


         与解码器相对的,MessageToByteEncoder编码器,也是个抽象基类,提供了抽象方法encode需要子类去实现,继承关系如下图:

在这里插入图片描述

         由继承关系图可以看出,MessageToByteEncoder继承了ChannelOutboundHandlerAdapter,是一个outbound出站处理器,重点关注其write方法,代码实现如下:

在这里插入图片描述

         代码逻辑还是比较清晰,就是调用encode编码,然后向下传播write事件。

         到这里就看到了Netty对自定义编解码的扩展,下面介绍Dubbo对扩展的自定义实现。



Dubbo协议实现源码分析



         编解码器本质上都是handler,所以先从Netty启动是往ChannelPipeline中添加handler开始看,以服务端为例,NettyServer#doOpen方法代码如下:

在这里插入图片描述

         标准的一个Netty服务器写法,里边可以看到编解码都由NettyCodecAdapter维护,NettyCodecAdapter代码如下:

在这里插入图片描述

         实现较为简单,维护了两个内部类,一个是InternalEncoder继承自MessageToByteEncoder,一个是InternalDecoder继承自ByteToMessageDecoder,实现了对应的编解码接口。以及维护了一个Code2类型的对象,Codec2也是一个扩展点,对应不同协议的实现,因为介绍Dubbo协议,所以此处是DubboCountCodec,DubboCountCodec代码如下:


在这里插入图片描述

         DubboCountCodec内部维护了一个DubboCodec,DubboCodec才是编解码具体实现,DubboCountCodec做的就是一次性读取更多完整报文编解码生成对象。DubboCodec继承关系如下图:

在这里插入图片描述



encode源码分析


         先介绍encode,DubboCountCodec调用encode之后,其具体实现逻辑位于ExchangeCodec#encode方法,实现代码如下:

在这里插入图片描述

         首先对需要编码的消息类型进行判断,如果是Request则调用encodeRequest,如果是Response则调用encodeResponse,如果都不是,则调用父类TelnetCodec的encode方法。先展开分析下encodeRequest方法,代码如下:

在这里插入图片描述

         实际上就是对开头所描述的Dubbo协议的构建,其中会调用encodeRequestData对RpcInvocation调用进行编码,代码如下:

在这里插入图片描述

         主要是将方法调用参数和值编码成字节流。包括框架版本、调用接口、方法名称、参数类型、参数值等信息。

         encodeResponse方法实现与encodeRequest方法实现十分相似,同样是对Dubbo协议字节流的构建,不再展开描述,主要介绍下其encodeResponseData方法,其data一半是Result类型,实现代码如下:

在这里插入图片描述

         主要完成对调用结果的序列化。




decode源码分析


         解码过程要比编码复杂一点,主要是需要解决粘包和半包问题,其实现位于ExchangeCodec#decode方法,实现代码如下:

在这里插入图片描述

         解码主要分为解码16字节报文头和解码报文体,具体的消息体解码位于DubboCodec#decodeBody方法中,具体代码如下:

在这里插入图片描述

         解码分为对request的解码和response的解码,虽然看上去很长,其实只是请求类型的分类,以及根据decode.in.io的配置值判断是在I/O线程中直接解码,还是交由业务线程池去解码。

         请求消息解码具体实现位于DecodeableRpcInvocation#decode方法,代码实现如下:

在这里插入图片描述

         主要逻辑是获取各项参数封装到当前的RpcInvocation对象中。

         响应消息解码的具体实现位于DecodeableRpcResult#decode中,具体代码实现如下:

在这里插入图片描述

         根据响应标记位,对各种情况下的响应做处理,正常情况下将返回数据反序列化后存到result字段中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,941评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,397评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,345评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,851评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,868评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,688评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,414评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,319评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,775评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,945评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,096评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,789评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,437评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,993评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,107评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,308评论 3 372
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,037评论 2 355