高性能序列化工具Google Protobuf的使用

序列化将对象转换成二进制数据反序列化是指将二进制数据转换成对象。

常用的跨语言的序列化与反序列化工具有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的优势。


上一篇:带你读《工业物联网安全》之二:工业物联网数据流和安全架构


下一篇:volatile与zookeeper