网易首页 > 网易号 > 正文 申请入驻

netty系列之:netty中的核心解码器json

0
分享至

简介

程序和程序之间的数据传输方式有很多,可以通过二进制协议来传输,比较流行的像是thrift协议或者google的protobuf。这些二进制协议可以实现数据的有效传输,并且通过二进制的形式可以节省数据的体积,在某些速度和效率优先的情况下是非常有效的。并且如果不同的编程语言之间的相互调用,也可以通过这种二进制的协议来实现。

虽然二进制更加快速和有效,但是对于程序员来说不是很友好,因为一个人很难直接读取二进制文件,虽然也存在一些一些文本的数据传输方式,比如XML,但是XML的繁琐的标签导致了XML在使用中有诸多的不便。于是一种通用的文本文件传输格式json诞生了。

能读到这篇文章的朋友肯定对json不陌生了,当然还有一些更加简洁的文件格式,比如YAML,感兴趣的朋友可以更深入的了解一下。

这里我们想要讲的是netty对json的解码。

java中对json的支持

在java中我们json的使用通常是将一个对象转换成为json进行数据传输,或者将接收到json进行解析,将其转换成为对象。

可惜的是在JDK中并没有提供给一个好用的JSON工具,所以我们一般需要借助第三方的JSON包来实现Object和JSON之间的转换工作。

通常使用的有google的GSON,阿里的FastJSON和jackson等。

这里我们使用google的GSON来进行介绍。

这里我们主要讲解的是java中对象和json的互相转换,所以GSON中其他更加强大的功能这里就不介绍了。

首先我们创建一个JAVA对象,我们定义一个Student类,如下所示:

static class Student {
String name;
String phone;
Integer age;

public Student(String name, String phone, Integer age) {
this.name = name;
this.phone = phone;
this.age = age;
}
}

这个类中,我们为Student定义了几个不同的属性和一个构造函数。接下来我们看下如何使用GSON来对这个对象进行JSON的转换:

Student obj = new Student("tina","188888888",18);
Gson gson = new Gson();
String json = gson.toJson(obj);
System.out.println(json);
Student obj2 = gson.fromJson(json, Student.class);
System.out.println(obj2);

GSON使用起来非常简单,我们构建好Gson对象之后,直接调用它的toJson方法即可将对象转换成为json字符串。

然后调用json的fromJson方法就可以将json字符串转换成为对象。

上面的代码输出如下:

{"name":"tina","phone":"188888888","age":18}
com.flydean.JsonTest$Student@4534b60d
netty对json的解码

netty为json提供了一个解码器叫做JsonObjectDecoder,先来看下JsonObjectDecoder的定义:

public class JsonObjectDecoder extends ByteToMessageDecoder

和前面讲解的base64,byte数组不同的是,JsonObjectDecoder继承的是ByteToMessageDecoder而不是MessageToMessageDecoder。

这说明JsonObjectDecoder是直接从ByteBuf转换成为Json Object对象。

我们知道JDK中并没有JSON这个对象,所有的对象都是从第三方包中引入的,netty并没有引入新的对象,所以netty中从Json中解析出来的对象还是一个ByteBuf对象,在这个ByteBuf中包含了一个Json对象。

JsonObjectDecoder的解析逻辑是怎么样的呢?

首先来看下JsonObjectDecoder中定义的4个state:

private static final int ST_CORRUPTED = -1;
private static final int ST_INIT = 0;
private static final int ST_DECODING_NORMAL = 1;
private static final int ST_DECODING_ARRAY_STREAM = 2;

ST_INIT表示的是decode的初始状态,ST_CORRUPTED表示的是decode中出现的异常状态。

ST_DECODING_NORMAL代表的是一个普通的json,如下所示:


"source": "web",
"type": "product_info",
"time": 1641967014440,
"data": {
"id": 30000084318055,
"staging": false
},
"dataId": "123456"

ST_DECODING_ARRAY_STREAM代表的是一个数组,对于数组来说,数组也是一个对象,所以数组也可以用json表示,下面就是一个常见的json数组:

[ "Google", "Runoob", "Taobao" ]

JsonObjectDecoder的解码逻辑比较简单,它主要是读取ByteBuf中的数据,通过判断读取的数据和json中特有的大括号,中括号,逗号等分隔符来分割和解析json对象。

要注意的是,JsonObjectDecoder要解码的ByteBuf中的消息应该是UTF-8编码格式的,为什么需要UTF-8格式呢?

这是因为json中那些特有的分隔符,即使在UTF-8中也是用一个byte来存储的,这样我们在读取数据的过程中,可以通过读取的byte值和json的分隔符进行比较,从而来确定json中不同对象的界限。

如果换成其他的编码方式,json中的分隔符可能会用多个byte来表示,这样对我们的解析就提高了难度,因为我们需要知道什么时候是分隔符的开始,什么时候是分隔符的结束。

它的核心解码逻辑如下,首先从ByteBuf中读取一个byte:

byte c = in.getByte(idx);

然后通过调用decodeByte(c, in, idx);来判断当前的位置是开括号,还是闭括号,是在一个对象的字符串中,还是一个新的对象字符串。

首先需要对当前的state做一个判断,state判断调用的是initDecoding方法:

private void initDecoding(byte openingBrace) {
openBraces = 1;
if (openingBrace == '[' && streamArrayElements) {
state = ST_DECODING_ARRAY_STREAM;
} else {
state = ST_DECODING_NORMAL;

接着就是对当前的state和自定义的4个状态进行比较,如果是普通的json对象,并且对象已经是闭括号状态,说明该对象已经读取完成,可以将其进行转换并输出了:

if (state == ST_DECODING_NORMAL) {
decodeByte(c, in, idx);
if (openBraces == 0) {
ByteBuf json = extractObject(ctx, in, in.readerIndex(), idx + 1 - in.readerIndex());
if (json != null) {
out.add(json);

如果state表示目前是一个数组对象,数组对象中可能包含多个对象,这些对象是通过逗号来区分的。逗号之间还可能会有空格,所以需要对这些数据进行特殊判断和处理,如下所示:

else if (state == ST_DECODING_ARRAY_STREAM) {
decodeByte(c, in, idx);

if (!insideString && (openBraces == 1 && c == ',' || openBraces == 0 && c == ']')) {
for (int i = in.readerIndex(); Character.isWhitespace(in.getByte(i)); i++) {
in.skipBytes(1);
}
int idxNoSpaces = idx - 1;
while (idxNoSpaces >= in.readerIndex() && Character.isWhitespace(in.getByte(idxNoSpaces))) {
idxNoSpaces--;
}
ByteBuf json = extractObject(ctx, in, in.readerIndex(), idxNoSpaces + 1 - in.readerIndex());
if (json != null) {
out.add(json);
}
....

最后将解析出来的json对象放入byteBuf的out list中,整个解析到此结束。

总结

以上就是netty中json核心解码器JsonObjectDecoder的使用,它的本质是通过判断json对象中的分割符来分割多个json字符串,然后将分割后的json字符串存入ByteBuf中输出。

看到这里,大家可能会疑惑了,decoder不是和encoder一起出现的吗?为什么netty中只有JsonObjectDecoder,而没有JsonObjectEncoder呢?

事实上,这里的Json对象就是一个包含Json字符的字符串,这个字符串被写入到ByteBuf中,所以这里并不需要特殊的encoder。

本文已收录于 http://www.flydean.com/14-3-netty-codec-json/

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
冒充职业球员?欧洲杯惊现200多斤大胖子 当年差点加盟中超

冒充职业球员?欧洲杯惊现200多斤大胖子 当年差点加盟中超

球事百科吖
2024-06-16 00:04:33
倒查30年后补税是个危险信号

倒查30年后补税是个危险信号

深度财线
2024-06-15 22:03:47
革命性突破!美企成功研制核电池,几乎无辐射,电量够用100年

革命性突破!美企成功研制核电池,几乎无辐射,电量够用100年

十三级台阶
2024-06-15 15:51:27
“复兴号”列车车厢转运过程中被货车撞上,交警:无人受伤

“复兴号”列车车厢转运过程中被货车撞上,交警:无人受伤

极目新闻
2024-06-15 22:36:25
五大名医集体总结:增强身体健康的10大铁律,值得参考~

五大名医集体总结:增强身体健康的10大铁律,值得参考~

华人星光
2024-06-15 16:49:27
4人被查,3人被处分……

4人被查,3人被处分……

黄河新闻网吕梁频道
2024-06-15 08:41:51
日本3-0塞尔维亚获8.68分:中国女排亚洲第1危矣 朱婷腰伤成X因素

日本3-0塞尔维亚获8.68分:中国女排亚洲第1危矣 朱婷腰伤成X因素

颜小白的篮球梦
2024-06-15 19:57:18
中俄联合开发黑瞎子岛,当年黑瞎子岛是怎样被俄方占领的?

中俄联合开发黑瞎子岛,当年黑瞎子岛是怎样被俄方占领的?

浩然史观
2024-06-15 16:55:02
大陆不再沉默,给黄仁勋上了一课,选在美收紧对华AI芯片出口之际

大陆不再沉默,给黄仁勋上了一课,选在美收紧对华AI芯片出口之际

陈菲副教授
2024-06-15 18:20:03
陪睡门曝光!双一流大学女生陷陪睡丑闻,交友App成道德沦丧背后推手?

陪睡门曝光!双一流大学女生陷陪睡丑闻,交友App成道德沦丧背后推手?

新青年大院NEWYOUTH
2024-06-16 00:06:48
欧洲杯高质量3-1!前国脚董方卓感慨:中国足球已跟不上时代步伐

欧洲杯高质量3-1!前国脚董方卓感慨:中国足球已跟不上时代步伐

黑色柳丁
2024-06-15 23:51:10
网传南方医科大学老师为抢救患儿迟到29分钟,被举报扣款2000元?

网传南方医科大学老师为抢救患儿迟到29分钟,被举报扣款2000元?

火山诗话
2024-06-16 06:51:58
一针69.7万,医保谈判到3万!可澳洲184块,为何却说中国价最低?

一针69.7万,医保谈判到3万!可澳洲184块,为何却说中国价最低?

风起云间
2024-06-14 21:44:22
女性私处的“芳草”,竟然是越“浓密”越“渴望”?

女性私处的“芳草”,竟然是越“浓密”越“渴望”?

水白头
2024-06-16 00:06:07
吕迪格回应定妆照争议手势:很多球员摆出这个姿势,没有宗教意涵

吕迪格回应定妆照争议手势:很多球员摆出这个姿势,没有宗教意涵

直播吧
2024-06-16 06:45:07
0-2到3-2!女排绝地反击,逆转世界第1,日本队空欢喜一场!

0-2到3-2!女排绝地反击,逆转世界第1,日本队空欢喜一场!

钉钉陌上花开
2024-06-15 22:43:32
欧洲杯被中文广告包围?破案了:均为虚拟广告牌,与现场不一样!

欧洲杯被中文广告包围?破案了:均为虚拟广告牌,与现场不一样!

风过乡
2024-06-15 16:53:50
31岁河南禹州市医保局局长任小龙,拟遴选进入省政府办公厅

31岁河南禹州市医保局局长任小龙,拟遴选进入省政府办公厅

澎湃新闻
2024-06-15 21:58:28
税太高了?一家企业要交13%增值税、25%企业所得税、20%分红税

税太高了?一家企业要交13%增值税、25%企业所得税、20%分红税

小蜜情感说
2024-06-16 07:50:02
追梦回应克莱取关勇士:我觉得这很好笑 你们都想看有人感到受伤

追梦回应克莱取关勇士:我觉得这很好笑 你们都想看有人感到受伤

罗说NBA
2024-06-16 05:19:26
2024-06-16 11:16:49
flydean程序那些事
flydean程序那些事
最通俗的解读,最深刻的干货!
356文章数 438关注度
往期回顾 全部

科技要闻

iPhone 16会杀死大模型APP吗?

头条要闻

40余套房屋涉嫌"一房多卖" 有购房者内心积郁因病去世

头条要闻

40余套房屋涉嫌"一房多卖" 有购房者内心积郁因病去世

体育要闻

没人永远年轻 但青春如此无敌还是离谱了些

娱乐要闻

江宏杰秀儿女刺青,不怕刺激福原爱?

财经要闻

打断妻子多根肋骨 上市公司创始人被公诉

汽车要闻

东风奕派eπ008售21.66万元 冰箱彩电都配齐

态度原创

旅游
房产
手机
亲子
军事航空

旅游要闻

@毕业生,江苏这些景区可享免票或优惠

房产要闻

万华对面!海口今年首宗超百亩宅地,重磅挂出!

手机要闻

这次稳妥了,小米15系列手机发布时间、配置信息都有了准信

亲子要闻

家庭教育争议:青春期孩子该如何管教?

军事要闻

普京提停火和谈条件 美防长迅速回应

无障碍浏览 进入关怀版