序列化指将对象转换成二进制数据,反序列化是指将二进制数据转换成对象。
常用的跨语言的序列化与反序列化工具有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的优势。