一、介绍
Google提供一个具有高效的协议数据交换格式工具库(类似Json),但相比于Json,Protobuf有更高的转化效率,时间效率和空间效率都是JSON的3-5倍。google 提供了三种语言的实现:java、c++ 和 python,每一种实现都包含了相应语言的编译器以及库文件。
二、特点
Xml、Json是目前常用的数据交换格式,它们直接使用字段名称维护序列化后类实例中字段与数据之间的映射关系,一般用字符串的形式保存在序列化后的字节流中。消息和消息的定义相对独立,可读性较好。但序列化后的数据字节很大,序列化和反序列化的时间较长,数据传输效率不高。
Protobuf和Xml、Json序列化的方式不同,采用了二进制字节的序列化方式,用字段索引和字段类型通过算法计算得到字段之前的关系映射,从而达到更高的时间效率和空间效率,特别适合对数据大小和传输速率比较敏感的场合使用。
三、结构
proto文件定义了协议数据中的实体结构(message ,field)。
举例如下:
//要生成的类Person
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
(1)关键字message: 代表了实体结构,由多个消息字段(field)组成。
Message中定义的全部属性在class中全部为private的。
Message的嵌套使用可以嵌套定义,也可以采用先定义再使用的方式。
(2)消息字段field: 即属性,包括字段规则+数据类型+字段名+属性顺序号+[默认值]。
-
数据类型:常见的原子类型都支持
-
字段规则:
- required:对于required的字段而言,必须初始化字段,否则会抛异常
- optional:可选字段,可以不必初始化。如果没初始化,那么将赋予该字段编号一个默认值。int或者char数据类型默认为0,string默认为"",bool默认为false,嵌套message默认为构造,枚举则为第一个。
- repeated:数据可以重复(相当于java 中的Array或List)
-
字段唯一标识:序列化和反序列化将会使用到。比如上面的=1; =2;
-
默认值:在定义消息字段时可以给出默认值。比如 [default = HOME]
四、选择版本
syntax 声明可以选择protobuf的编译器版本(v2和v3)
- syntax="proto2":选择2版本,各个字段必须明确标注编号以确定序列化后二进制数据字段的位置
- syntax="proto3":选择3版本,没有强制使用字段编号,proto3 已舍弃 required 字段,optional 字段也无法显示使用
五、Intellij IDEA中使用Protobuf
1、下载个protoc.exe
- 官网下载地址:http://code.google.com/p/protobuf/downloads/list
- protoc的源码和各个系统的预编译包:https://github.com/protocolbuffers/protobuf/releases
在里面下载个protobuf-java-3.7.1.zip,解压后bin里面有protoc.exe,下载完以后放到项目的resourceproto下。
2、编辑个.proto文件
在proto文件下创建一个AddressBook.proto。用的是proto2版本
里面的结构就是 AddressBook下有很多个Person。
每个Person必须有一个name、必须有一个id、可选有email、很多个PhoneNumber。
每个PhoneNumber必须有一个number、可选PhoneType。
PhoneType取值必为0或1或2
写的内容举例如下:
syntax = "proto2";
//生成的类会放在protoc.exe同目录下的tutorial
//如果.proto文件中写了java_package,就以java_package为准。
package beans;
//生成的类会放在protoc.exe同目录下的com.proto.tutorial下
//option java_package = "com.proto.tutorial";
//最终成的类名
//option java_outer_classname = "AddressBookProtos";
message Person {
required string name = 1;
required int32 id = 2; .
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
package tutorial;
option java_package = "com.proto.tutorial";
option java_outer_classname = "AddressBookProtos";
message Person {
required string name = 1;
required int32 id = 2; // Unique ID number for this person.
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
}
3、将.proto文件转成Java类
控制台中执行protoc命令,依次将.proto文件转成Java类
protoc.exe -I=F:/workspace/proto-test/src/main/resources/proto --java_out=F:/workspace/proto-test/src/main/java/beans F:/workspace/proto-test/src/main/res
ources/proto/AddressBook.proto
protoc.exe -I=(proto文件所在绝对路径,不包括proto文件本身) --java_out=(文件输出目录) (proto文件所在绝对路径,包括proto文件名)
4、相关包
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.7.1</version>
</dependency>
<dependency>
<groupId>com.googlecode.protobuf-java-format</groupId>
<artifactId>protobuf-java-format</artifactId>
<version>1.2</version>
</dependency>
5、.proto文件语法高亮显示
需要安装Protobuf Support插件,
依次点击Intellij中的“File”-->"Settings"-->"Plugins"-->"Browse repositories",
输入Protobuf,点击install
6、具体使用举例
AddressBookProtos.AddressBook .Builder addressBook= AddressBookProtos.AddressBook .newBuilder();
AddressBookProtos.Person .Builder person= AddressBookProtos.Person .newBuilder();
person.setName("Mike");
addressBook.setPerson(person);