每一秒钟的时间都值得铭记

0%

ProtoBuf入门

什么是 ProtoBuf

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。

Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。

ProtoBuf 是一种结构数据序列化的方法,类似于 XMLJson 等数据序列化格式,具有语言无关、平台无关、可扩展、灵活高效等特点。

怎么使用 ProtoBuf

下载 protoc 编译器

在使用 ProtoBuf 之前,需要先下载 ProtoBuf 编译器

下载地址:https://github.com/protocolbuffers/protobuf/releases

下载之后将压缩包放置到工作目录下,并解压到当前文件夹,将 bin 目录下的 protoc 可执行文件复制到工作目录下即可。

定义数据结构

ProtoBuf 使用 .proto 文件来进行数据结构的定义。

protoc 可执行文件的同级别目录下创建一个 .proto 文件,并在文件中定义数据结构。

例如:编写一个 user.proto 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
syntax = "proto3";

package user;

// 编译生成的Java可读写文件是否多文件生成
option java_multiple_files = false;
// 编译生成的Java文件的目录,该目录可以由protoc编译器自动生成
option java_package = "com.herenpeng.proto";
// 编译生成的Java可读写文件名称,最终Java文件路径为 com.herenpeng.proto.UserProto
option java_outer_classname = "UserProto";

// 定义一个User数据结构
message User {
int32 id = 1; // 定义一个int32类型的id属性
string name = 2; // 定义一个string类型的name属性
string email = 3; // 定义一个string类型的email属性

// 定义一个枚举类型
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}

// 定义一个手机号数据结构
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}

// 定义一个PhoneNumber集合类型的phones属性
repeated PhoneNumber phones = 4;
}

protoc 编译可以读写的接口文件

进入当前工作目录下的命令行界面,直接 protoc 编译命令,即可生成 ProtoBuf 可读写的Java接口文件。

1
protoc ./user.proto --java_out=./
  • 第一个参数:protoc 编译器可编译的 .proto 文件的路径。
  • 第二个参数 --java_out=:为 protoc 编译器编译之后,生成的 Java 可读写文件的路径。(该路径需要手动创建,protoc无法自动创建)

如果在开发中需要频繁进行编译生成工作,可以考虑将命令写成一个 .bat.sh脚本,将输出如今直接指向项目中的包路径。如果编译输出的路径不是在项目的包下,则需要自己手动将编译生成的接口文件复制到项目对应的目录下。

例如:

1
protoc ./*.proto --java_out=../src/main/java

引入 ProtoBuf 依赖

在项目中使用 ProtoBuf ,需要引入 ProtoBuf相关的依赖。

在引入依赖的时候需要注意一点,引入的 ProtoBuf 依赖的版本尽量与 protoc 编译器的版本保持一致,如果版本不同,可能会出现一些不兼容的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.19.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>

调用接口序列化数据

ProtoBuf可以调用 Builder 接口进行属性设置,属性设置完成之后则使用 build() 方法进行数据构造,最后使用 toByteArray() 生成字节数组。

1
2
3
4
5
6
7
8
9
10
11
12
UserProto.User.Builder user = UserProto.User.newBuilder();
user.setId(1);
user.setName("小明");
user.setEmail("xiaoming@qq.com");

UserProto.User.PhoneNumber.Builder phoneNumber = UserProto.User.PhoneNumber.newBuilder();
phoneNumber.setNumber("18478524512");
phoneNumber.setType(UserProto.User.PhoneType.HOME);
user.addPhones(phoneNumber);

System.out.println(user.build());
System.out.println(Arrays.toString(user.build().toByteArray()));

ProtoBuf 的优缺点

ProtoBufXMLJson都是序列化数据的方式,但是这三者直接还是有一些差异的,所使用的场景也各不相同。

  • ProtoBuf 更加注重效率,序列化之后是字节数组,数据更小、传输速率更快,但是人类可读性差。

  • XMLJson 序列化之后的数据人类可读性强。

坚持原创技术分享,您的支持将鼓励我继续创作!
-------------这是我的底线^_^-------------