序列化指将对象转换成二进制数据,反序列化是指将二进制数据转换成对象。
常用的跨语言的序列化与反序列化工具有JSON,XML(XStream),JBoss的Marshalling,Apache的Thrift,Google的ProtoBuf等,JAVA语言还有Serializable和自定义的Externalizable。
由于最近一个项目中有一个协议优化,将原本的XML方式改为一个压缩率高的方式,优先想到的是JSON,但最近一些公司的技术开源使得很多更好的工具出现了,Google开源的protobuf就一个相当优秀的工具,结合我的使用和测试,这里简单地介绍一下我是如何在JAVA环境下运用的。
首先要下载protobuf的工具包,包括protobuf-java和对应版本的protoc.exe文件,我是在maven的中央仓库里下的,CSDN里也有提供下载的地址。
然后就是编写proto文件,我写的demo如下:
option java_package = "com.vince.im.protocol";
option java_outer_classname = "BaseProtocol";
message SNMessage {
optional string protocol = 1;
required string version = 2;
required string operation = 3;
message Member {
required string id = 1;
optional string name = 2;
}
message Data {
optional string type = 1;
optional string auth = 2;
optional string from = 3;
optional string to = 4;
optional string sender = 5;
optional string sendate = 6;
optional string conent = 7;
optional string media = 8;
optional string filename = 9;
repeated Member members = 10;
}
repeated Data data = 4;
}
proto文件的编写也有自己的语法规则,例如message,optional,required,string都有特定的意义(详细参考官方的指导文档),主要包括如下:
定义一个消息(message)类型
标量值类型
可选的(optional)字段以及默认值
枚举
使用其他消息类型
嵌套类型
更新一个消息类型
扩展
包(package)
定义服务(service)
选项(option)
生成访问类
最上面是申明生成JAVA文件的包名和类名,下面的SNMessage是定义的一个消息,string表示的是字符类型,required表示是必有项,optional则表示是可选项,后面的数字是指定的序列位置。
我写了一个bat文件用于生成对应的JAVA文件
cd E:\work\workspace\im
protoc.exe --java_out=./src ./Message.proto > out.txt
结果生成了com.vince.im.protocol.BaseProtocol类。
接下来就是如何用这个类进行序列化和反序列化了,序列化的代码如下:
BaseProtocol.SNMessage.Member.Builder m = BaseProtocol.SNMessage.Member.newBuilder();
m.setId("13075694");
m.setName("Vince");
BaseProtocol.SNMessage.Data.Builder d = BaseProtocol.SNMessage.Data.newBuilder();
d.setAuth("123qweasd");
d.setFilename("beauty");
d.setFrom("13075694");
d.setTo("13075695");
d.setMedia("image");
d.setConent("hello world test");
d.setSendate("2014-09-09-09:53");
d.setSender("vince");
d.setType("text");
d.addMembers(m);
BaseProtocol.SNMessage.Builder snmessage = BaseProtocol.SNMessage.newBuilder();
snmessage.setProtocol("snchat");
snmessage.setVersion("1.0.0");
snmessage.setOperation("1000");
snmessage.addData(d);
BaseProtocol.SNMessage s = snmessage.build();
byte[] data = s.toByteArray()
反序列化如下:
BaseProtocol.SNMessage s2 = BaseProtocol.SNMessage.parseFrom(data);
这里我做了一个用protobuf和json的对比,单次运行结果如下:
JSON encode time : 1699 ms
JSON decode time : 55 ms
292 Bytes
{"datas":[{"auth":"123qweasd","conent":"hello world test","filename":"beauty","from":"13075694","media":"image","members":[{"id":"13075694","name":"Vince"}],"sendate":"2014-09-09-09:53","sender":"vince","to":"13075695","type":"text"}],"operation":"1000","protocol":"snchat","version":"1.0.0"}
-----------------------
prtoBuf encode time : 192 ms
prtoBuf decode time : 7 ms
137 Bytes
protocol: "snchat"
version: "1.0.0"
operation: "1000"
data {
type: "text"
auth: "123qweasd"
from: "13075694"
to: "13075695"
sender: "vince"
sendate: "2014-09-09-09:53"
conent: "hello world test"
media: "image"
filename: "beauty"
members {
id: "13075694"
name: "Vince"
}
}
从结果可以很明显的看出protobuf的优势。