序列化技术ProtoBuf
ProtoBuf :https://developers.google.cn/protocol-buffers
1.什么是序列化
把对象内容转化成数据流;
与之对应的就是反序列化:从数据流中读取数据,然后重新转换成对象;
序列化反序列化往往是遵循一定的格式来操作的;
常见的序列化有:把对象转成XML,JSON,二进制流
特点 | XML | JSON | ProtoBuf |
---|---|---|---|
数据结构 | 复杂 | 简答 | 较复杂 |
保存方式 | 文本 | 文本 | 二进制 |
保存大小 | 大 | 一般 | 小 |
解析速度 | 慢 | 一般 | 快 |
语言支持 | 多 | 多 | C/Java/py |
开发难易 | 麻烦 | 简答 | 简答 |
2.跨平台序列化
我的理解是序列化就是为了跨平台而来的,不同平台之间要相互通信,对象序列化就要遵循相互的规则;
一般跨平台的东西,很明显都需要一个中间量来过滤,比如Java 跨平台,就需要class 文件就相当于是模板,Thrift 跨平台rpc ,就需要定义格式文件 .thrift ;同样我们的ProtoBuf 是一款跨平台序列胡工具也是需要来定义 .proto
3.安装
我是windows 上测试的 直接下载对应版本 https://github.com/protocolbuffers/protobuf/releases/tag/v21.4
安装好环境变量 执行 有版本信息就表示OK
C:\Users\sff>protoc --version
libprotoc 2.5.0
4.模板学习
类型学习
https://developers.google.cn/protocol-buffers/docs/proto
// 声明语法开头
syntax = "proto2";
//避免在 Protocol Buffers 名称空间以及非 Java 语言中的名称冲突。
package tutorial;
option java_multiple_files = true;
// java 对应的包和类
option java_package = "com.example.tutorial.protos";
//。如果你没有java_outer_classname明确给出a,它将通过将文件名转换为大写驼峰式来生成
option java_outer_classname = "AddressBookProtos";
message Person {
//标准的简单数据类型可用作字段类型 optional: 该字段可以设置也可以不设置 required:必须提供该字段的值,否则该消息将被视为“未初始化”
// repeated:该字段可以重复任意次数 required字段是非常不受欢迎的
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
optional string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
生成java代码 (也可以生成其他语言的代码)
protoc addressbook.proto --java_out=D:\Resource\FrameMiddleware\proto\template
标准消息方法
每个消息和构建器类还包含许多其他方法,可让您检查或操作整个消息,包括:
isInitialized()
: 检查是否所有必填字段都已设置。toString()
:返回消息的人类可读表示,对于调试特别有用。mergeFrom(Message other)
:(仅限构建器)将 的内容other
合并到此消息中,覆盖单个标量字段,合并复合字段,并连接重复的字段。clear()
:(仅限构建器)将所有字段清除回空状态。
这些方法实现了所有 Java 消息和构建器共享的Message
和接口。Message.Builder
有关更多信息,请参阅完整的 API 文档Message
。
解析和序列化
最后,每个协议缓冲区类都有使用协议缓冲区二进制格式写入和读取您选择的类型的消息的方法。这些包括:
byte[] toByteArray();
:序列化消息并返回包含其原始字节的字节数组。static Person parseFrom(byte[] data);
: 从给定的字节数组中解析消息。void writeTo(OutputStream output);
: 序列化消息并将其写入OutputStream
.static Person parseFrom(InputStream input);
: 读取并解析来自InputStream
.
5.测试
生成的代码导入 添加maven
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.30.2</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.30.2</version>
</dependency>
<!-- 用于对比测试-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
</dependencies>
java 测试代码
public class Main {
public static void main(String[] args) {
Person build = Person.newBuilder().setEmail("aaaaa").setName("zhangsan").setId(10).build();
System.out.println(build);
byte[] bytes = build.toByteArray();
System.out.println("bp size =" + bytes.length + "B");
PersonB personB = new PersonB("aaaaa", "zhangsan", 10);
byte[] bytes1 = JSONObject.toJSONString(personB).getBytes();
System.out.println(JSONObject.toJSONString(personB));
System.out.println("fastjson size =" + bytes1.length + "B");
}
}
结果
name: "zhangsan"
id: 10
email: "aaaaa"
bp size =19B
{"email":"aaaaa","id":10,"name":"zhangsan"}
fastjson size =43B
实际测试下来是相差一半的,不过我这个测试只是一个不太严谨的测试。。。。。
6.Avro
对比与pb Avro 是java编写的,也是一个跨语言的序列化工具 ,套路其实差不多