Protobuf IDL 支持
本页说明 Apache Fory 如何处理 Protocol Buffers(.proto)schema、protobuf 概念如何映射到 Fory,以及 protobuf 专用 Fory 扩展选项的使用方式。
本页内容
- 如何在具体场景下选择 protobuf 或 Fory
- 迁移时需要关注的语法与语义差异
.proto文件中支持的 Fory 扩展选项- 从 protobuf 迁移到 Fory 的实践路径
快速决策指南
| 场景 | 建议格式 |
|---|---|
| 主要构建 gRPC API,依赖 protobuf 工具链 | Protocol Buffers |
| 需要极致对象图性能与引用跟踪 | Fory |
| 需要在序列化数据中表达循环/共享引 用 | Fory |
| 需要强 unknown-field 语义保证线格式兼容 | Protocol Buffers |
| 希望直接使用原生 struct/class,而非 protobuf 包装类型 | Fory |
Protobuf 与 Fory 对比
| 维度 | Protocol Buffers | Fory |
|---|---|---|
| 主要目标 | RPC/消息契约 | 高性能对象序列化 |
| 编码模型 | Tag-Length-Value | Fory 二进制协议 |
| 引用跟踪 | 非内建 | 一等支持(ref) |
| 循环引用 | 不支持 | 支持 |
| 未知字段 | 保留 | 不保留 |
| 生成类型 | protobuf 专用模型类型 | 语言原生构造 |
| gRPC 生态 | 原生成熟 | 持续建设中(活跃开发) |
Fory 的 gRPC 支持仍在持续开发中。当前生产级 gRPC 工作流里,protobuf 仍是更成熟的默认选择。
为什么使用 Apache Fory
- 代码更贴近语言习惯:Fory IDL 生成的类和结构体可直接作为业务领域对象使用。
- 序列化性能更高:在 Fory 基准中,Fory 在对象序列化场景中可显著快于 protobuf。
- 对象图表达更自然:共享引用和循环引用是内建能力,无需通过业务层 ID 关联绕过。
性能细节请参见 性能参考。
语法与语义映射
Package 与文件级选项
协议缓冲(Protocol Buffers / Protobuf)
syntax = "proto3";
package example.models;
option java_package = "com.example.models";
option go_package = "example.com/models";
Fory
package example.models;
Fory 使用统一 package 命名空间做跨语言注册。语言特定的包路径仍可在代码生成阶段单独配置。
Message 与 Enum 定义
协议缓冲(Protocol Buffers / Protobuf)
message User {
string id = 1;
string name = 2;
optional string email = 3;
int32 age = 4;
repeated string tags = 5;
map<string, string> metadata = 6;
}
enum Status {
STATUS_UNSPECIFIED = 0;
STATUS_ACTIVE = 1;
}
Fory
message User [id=101] {
string id = 1;
string name = 2;
optional string email = 3;
int32 age = 4;
list<string> tags = 5;
map<string, string> metadata = 6;
}
enum Status [id=102] {
UNKNOWN = 0;
ACTIVE = 1;
}
关键差异:
- Fory 可直接分配稳定类型 ID(
[id=...])。 - Fory 使用
list<T>(repeated T为兼容别名)。 - 枚举命名更偏向语言习惯,而非 protobuf 前缀风格。
oneof 到 union
protobuf 的 oneof 会被翻译为嵌套 Fory union,并增加一个可选字段指向该 union。
协议缓冲(Protocol Buffers / Protobuf)
message Event {
oneof payload {
string text = 1;
int32 number = 2;
}
}
转换后的 Fory 结构
message Event {
union payload {
string text = 1;
int32 number = 2;
}
optional payload payload = 1;
}
说明:
- union case ID 来自原
oneof字段号。 - 自动生成的 union 引用字段使用
oneof中最小字段号。