前言
这一系列文章主要是对protobuf这种编码格式的使用方式、特点、使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务
什么是protobuf
protobuf是由google推出一种数据编码格式,不依赖平台和语言,类似于xml和json。然而与xml和json最大的不同之处在于,protobuf并非是一种可以完全自解释的编码格式,这点在之后会有说明
为什么要使用protobuf
同样作为一种编码方式,protobuf的解析速度更快,编码后的字节数更少。
其中解析速度的相关比较可以参看相关文章,这并不是本系列关心的重点,而字节数的减少将会是后续扩展和优化的重点
比json和xml更便利的是,开发者只需要编写一份.proto的描述文件,就可以通过google提供的编译器生成不同平台的模型代码,包括java、C#等等,而不需要手动进行模型编写
后续的示例都是采用java进行展示
基本的使用方式
首先,不同于使用某种具体的编程语言,模型文件是以.proto的描述文件形式进行定义的,在此文件中标识了模型的名字、字段类型、字段名字等、字段顺序(这个属性对于protobuf及其重要,会在下一篇原理中详细描述)等
例如下面这个例子:
syntax = "proto3";
package tutorial;
option java_package = "cn.tera.protobuf.model";
option java_outer_classname = "AddressBookProtos";
message Person {
required string name = 1;
required int32 id = 2;
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
第一行定义的是语法,现在有proto3和proto2两种版本,如果不定义,则默认proto2,后续的描述都以proto3版本为主
package是用来区分命名空间的,如果生成的是java,也会被默认成java的package,当然可以通过java_package另外指定。
如果指定了java_outer_classname,则生成的java文件的类名将会以此为准,且该文件中定义的所有类都会在被包含在该类之内
在Person内定义了模型的名字,之后是字段的类型、名称、顺序
required表示必须字段,在编码和解码时,该字段必须有值,否则就会失败(不建议使用)
optional表示可选字段,在proto3的语法中可以省略
repeated表示可重复字段,对应于java中的List或者array
编译文件
编译器下载地址
https://github.com/protocolbuffers/protobuf/releases/tag/v3.12.1
之后执行命令
/Users/tianjiyuan/Documents/protobuf/protoc -I=/Users/tianjiyuan/Documents/blogs/protobuf/proto --java_out=/Users/tianjiyuan/Documents/blogs/protobuf/src/main/java/ /Users/tianjiyuan/Documents/blogs/protobuf/proto/AddressBookProtos.proto
注意,对于生成的java模型,编译器会自动生成在.proto文件中定义的java_package文件夹,所以--java_out参数可以直接指定到项目的java source目录,生成出的.java文件就会直接位于项目中了,十分方便
其中ProtobufTest.basicUse展示了protobuf的基本使用方法
proto文件夹中是所有后面会用到的.proto文件
protobuf和json的互相转换
因为现在json格式的数据交互相对比较主流,因此当我们考虑使用protobuf时,需要考虑的第一个问题就是protobuf能否方便地和json进行格式转换。答案是肯定的。
maven依赖
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.9.1</version>
</dependency>
demo中的ProtobufTest.jsonToProtobuf展示了protobuf与json互相转换