§1 基本介绍
基本信息
- Google Protocol Buffers
- 序列化技术
- 通过 Message 的形式管理数据
- 可以自动生成 java 代码
支持用.proto
文件描述 java 类,并通过 protoc.exe 编译器自动生成代码
优点
- 跨平台、跨语言
- 高性能、高可靠性
应用
- rpc 序列化
- 编解码器
通常结合 Netty 应用,Netty 自带的编解码器底层是 JDK 的序列化- 体积大
- 性能低
- 不能跨语言
§2 .proto
文件
单数据类型示例
// 版本
syntax = "proto3"
// 文件名,类名
option java_outer_className = "EntityPOJO"
// message 体,相当于 AVRO 里的 schema
// 对应 EntityPOJO 的内部类
// 实际的 java bean 类
message Entity{
// 属性的 proto 类型,属性名,属性序号
int32 id = 1;
string name = 2;
}
类型
- double:double
- float:float
- int32:int
- int64:long
- uint32:unsigned int
- uint64:unsigned long
- sint32:int
- string:String
- bytes:ByteString
编译
用于生成 EntityPOJO.java
(按上面示例中 java_outer_className
)
protoc.exe --java_out=. 文件名
混合数据类型示例
// 版本
syntax = "proto3"
// 快速解析
option optimize_for = SPEED;
// java 包名
option java_package = "com.xx.xx.xx"
// java 文件名,类名
option java_outer_className = "DataInfo"
// 控制用的 message
message Dispatcher{
// 数据类型枚举
// proto 文件中,枚举编号从 0 开始
enum DataTyPe{
EntityType = 0;
DomainType = 1;
}
// 属性的 proto 类型(就是上面的枚举),属性名,属性序号
DataType dataType = 1;
// 下面属性不能同时出现,只能出现其中一个
// 如下例,entity 和 domain 是 message 的第二、第三属性,但二者不共存
oneof dataBody(
Entity entity = 2;
Domain domain = 3;
)
}
// message 体,相当于 AVRO 里的 schema
// 对应 DataInfo 的内部类
// 实际的 java bean 类
message Entity{
// 属性的 proto 类型,属性名,属性序号
int32 id = 1;
string name = 2;
}
message Domain{
int32 id = 1;
string name = 2;
int32 age=3;
}
§3 使用
注册 ProtoBuf 编解码器
ch.pipeline().addLast(new ProtoBufEncoder(EntityPOJO.Entity.getDefaultInstance()));
ch.pipeline().addLast(new ProtoBufDecoder(DataInfo.Dispatcher.getDefaultInstance()));
创建对象并发送 (以混合类型为例)
DataInfo data = DataInfo.Dispatcher.newBuilder()
.setDataType(DataInfo.Dispatcher.DataType.EntityType)
.setEntity(DataInfo.Entity.newBuilder.setId(1).setName("name").build())
.build();
ch.writeAndFlush(data);
接收对象 (以混合类型为例)
DataInfo.Dispatcher.DataType dataType = msg.getDataType();
if(DataInfo.Dispatcher.DataType.Entity == dataType){
DataInfo.Entity entity = msg.getStudent();
System.out.println("Entity: " + entity);
}else if(DataInfo.Dispatcher.DataType.Domain == dataType){
// do
}else{
// do
}