一、亮点简介
二、使用指南
1.定义.proto文件
2.编译.proto文件
3.读写数据
三、本文总结
四、参考资料
Protocol Buffers一种结构化数据存储格式。特点:快、小
序列化空间开销
解析耗时性能
小结:根据上图测评,序列化后的空间开销与解析性能上,Avro与Protobuf不相上下独占鳌头;另外根据“Protobuf协议介绍及性能实测”文中测评来看,报文在几千个字节以内,Protobuf与JSON/XML并没有太大优势,而hessian2表现更优秀;当报文大小超过10万字节,Protobuf性能是XML的3倍,是JSON的2倍,Hessian2的2倍;当报文大小超过10万字节,序列化后的字节大小约XML的1/4,约JOSN的1/2,约Hessian2的1/3;高性能原因Protobuf优化的二进制消息格式,JSON/XML是文本描述的;适用于性能要求高的RPC调用。
以下面addressbook.proto为例来看下.proto的语法。
syntax = "proto3"; // @1
package tutorial; // @2
import "google/protobuf/timestamp.proto"; // @3
option java_package = "com.example.tutorial"; // @4
option java_outer_classname = "AddressBookProtos"; // @5
message Person { // @6
string name = 1; // @7
int32 id = 2; // @8
string email = 3;
enum PhoneType { // @9
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4; // @10
google.protobuf.Timestamp last_updated = 5; // @11
}
message AddressBook { // @12
repeated Person people = 1; // @13
}
代码备注 @1 定义proto的版本 @2 定义proto的包名 @3 导入其他的.proto文件 @4 option可选的;指java类生成所在的包,如果没有指定包名采用默认包名 @5 option可选的;指生成的class类名,如果没有指定根据.profo文件名称驼峰命名 @6 定义消息类型,定义Person的消息格式 @7 定义字段类型string @8 定义字段类型整型 @9 定义枚举类型,枚举类型需整型值范围 @10 表示该值可重复,详单于java中的list @11 引用的时间类型生成的代码为:com.google.protobuf.Timestamp lastUpdated_ @12 定义消息类型,定义AddressBook的消息格式 @13 表示该值可重复,相当于Java中List
定义一个Service
service SoaInvokerService {
rpc call (SoaInvokerRequest) returns (SoaInvokerResponse);
}
备注:定义一个消息类型SoaInvokerService用在RPC的调用中。编译器会根据不同的语言生成不同的服务代码与存根。上面Service在通过编译器Java会生成SoaInvokerService的抽象类及存根。
2.编译.proto文件
通过下面命令生成Java代码,编译器为为每个消息类型生成一个.java文件以及特殊的Build类用于创建该类实例的接口。
bin/protoc --java_out=output example/addressbook.proto
使用方式
Person person = Person.newBuilder()
.setId(1)
.setName("zhansan")
.build(); // @1
person.toByteArray(); // @2
Person.parseFrom(byte[] data); // @3
person.writeTo(OutputStream out); // @4
Person.parseFrom(InputStream input) // @5
Person.Builder personBuilder = Person.newBuilder();
personBuilder.mergeFrom(); // @6
代码备注 @1 使用了Builder设计模式构建对象 @2 将消息对象Person序列化为byte数组 @3 将byte数组转换为消息对象Person @4 序列化该消息对象Person并写入到OutputStream @5 从InputStream读取并解析成消息对象Person @6 将同类消息merge到一起 备注:编译器下载地址:https://github.com/protocolbuffers/protobuf/releases
写数据
AddressBook.Builder addressBook = AddressBook.newBuilder();
addressBook.addPeople(
PromptForAddress(new BufferedReader(new InputStreamReader(System.in)),
System.out)); // @1
FileOutputStream output = new FileOutputStream(args[0]);
addressBook.build().writeTo(output); // @2
代码备注 @1 添加People到地址本 @2 通过writeTo方法将消息地址本写到到本地文件中
存储内容:address.store
strings address.store
zhansan
zhanshan@126.com"
13113133421
读数据
AddressBook addressBook =
AddressBook.parseFrom(new FileInputStream(args[0])); // @1
for (Person person: addressBook.getPeopleList()) {
System.out.println("Person ID: " + person.getId());
System.out.println(" Name: " + person.getName());
}
@1 通过parseFrom将输入流转换为AddressBook消息对象
内容输出
Person ID: 1
Name: zhansan
E-mail address: zhanshan@126.com
Mobile phone #: 13113133421
Person ID: 2
Name: lisi
E-mail address: lisi@126.com
Mobile phone #: 13164140909
示例代码 https://github.com/protocolbuffers/protobuf/tree/master/examples
本文根据测评结果,简单分析了Protocol Buffers的亮点:快、小;以及protobuf编译工具的使用;编译工具生成Java代码消息对象方法的使用;通过示例解读了生成二进制消息格式的读写方式。
1.[译]Protobuf 语法指南
https://colobu.com/2015/01/07/Protobuf-language-guide/
2.Protocol Buffers指南
https://developers.google.com/protocol-buffers/docs/javatutorial?hl=zh-cn
3.protobuf协议介绍及性能实测
https://lupeier.com/post/protobuf-introduce-and-test/
4.序列化和反序列化
https://tech.meituan.com/2015/02/26/serialization-vs-deserialization.html