Protobuf
什么是Protobuf
Protobuf(Protocol Buffers)协议😉 Protobuf 是一种由 Google 开发的二进制序列化格式和相关的技术,它用于高效地序列化和反序列化结构化数据,通常用于网络通信、数据存储等场景
为什么要使用Protobuf
其实 Protobuf 在许多领域都得到了广泛应用,特别是在分布式系统、RPC(Remote Procedure Call)框架和数据存储中,它提供了一种高效、简洁和可扩展的方式来序列化和交换数据,Protobuf 的主要优点包括:
- 高效性:Protobuf 序列化后的二进制数据通常比其他序列化格式(比如超级常用的JSON)更小,并且序列化和反序列化的速度更快,这对于性能敏感的应用非常有益。
- 简洁性:Protobuf 使用一种定义消息格式的语法,它允许定义字段类型、顺序和规则(消息结构更加清晰和简洁)
- 版本兼容性:Protobuf 支持向前和向后兼容的版本控制,使得在消息格式发生变化时可以更容易地处理不同版本的通信。
- 语言无关性:Protobuf 定义的消息格式可以在多种编程语言中使用,这有助于跨语言的通信和数据交换(截至本文发布目前官方支持的有C++/C#/Dart/Go/Java/Kotlin/python)
- 自动生成代码:Protobuf 通常与相应的工具一起使用,可以自动生成代码,包括序列化/反序列化代码和相关的类(减少了手动编写代码的工作量,提高效率,后面的🌰里有保姆级操作指南)
Protobuf实战
环境配置
首先我们需要在 pom.xml
文件中添加如下依赖:
xml
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.20.3</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.20.3</version>
</dependency>
接着如果你希望.proto
文件可以被idea识别的话,就需要安装 Protobuf
插件(非必要)
创建文件
然后我们创建一个.proto
文件,如下图(完整代码在文末附录)
其中 syntax = "proto3"
表示协议版本,option java_package = "com.aqin.protobuf"
表示生成的类所处的层级,option java_multiple_files = true
表示需要將生成的类拆分为多个(false
的话就是不需要),MyRequest
和 Header
是消息结构。
进入到文件📃AQin.proto
所在目录下,执行如下代码:
css
protoc -I=./ --java_out=./ ./AQin.proto
参数说明:
-I
用于指定.proto
文件所在的路径(也可以用-proto_path
代替)--java_out
用于指定生成的 java 文件的路径./AQin.proto
就是需要编译的.proto
文件
有一点需要注意的是这三个路径要使用相对路径就都使用相对路径,要使用绝对路径就都使用绝对路径(不要混着用),执行完成后,就会在指定的位置生成指定的文件,如下图
然后我们就可以通过生成的Java类来对接收到的信息进行解析,或者封装数据进对象进行发送
解析/封装数据
常用API
-
newBuilder()
:用于创建Java类(通过.proto
文件生成的)并返回该对象setXXX()
:设置属性值getXXX()
:获取属性值
-
byte[] toByteArray()
:用于序列化信息并返回一个字节数组 -
writeTo(OutputStream output)
: 序列化信息并写入一个输出流 -
parseFrom(byte[] data)
:解析传入的字节数组(一般用于接收数据) -
parseFrom(InputStream input)
:解析传入的输入流(一般用于接收数据)
那我们上面的AQin.proto
举个🌰
java
MyInfo myInfo = MyInfo.newBuilder().setName("Zhangsan");
Body body = Body.newBuilder().setMyInfo(myInfo).build();
ByteBuffer byteBuffer = ByteBuffer.allocate(body.toByteArray().length);
body.writeTo(CodedOutputStream.newInstance(byteBuffer));
//然后就可以发送了~~
附录
AQin.proto 完整代码
ini
//协议版本
syntax = "proto3";
//生成的类所处的层级
option java_package = "com.aqin.protobuf";
//是否需要將生成的类拆分为多个
option java_multiple_files = true;
// request
message MyRequest{
Header header = 1;
Body body = 2;
}
//Header
message Header {
uint32 RequestId = 1;
int64 Timestamp = 2;
}
//Body
message Body {
MyInfo Info = 1; //消息
ServiceResult serviceResult = 2; //结果反馈
}
message MyInfo{
string name = 1;
string age = 2;
}
message ServiceResult{
uint32 ErrorCode = 1;
string ErrorMsg = 2;
}