Protostuff

关注
义项:Java 序列化库
Protostuff

Protostuff是面向 Java 的序列化库,最初以 com.dyuproject.protostuff 为坐标发布于 2009 年,后迁移到 io.protostuff 组织下维护,最新版本为 1.8.0。[1][2] 它基于谷歌的 Protocol Buffers 数据格式,内置前后向兼容(模式演进)与校验支持,既可以把已有的 POJO 直接序列化为二进制流,也可以按 .proto 文件生成代码,常用于 RPC 消息传输与数据存储格式。[3][4]

百科 图文
目录
  1. 定义
  2. 原理
  3. 发展历程
  4. 应用
  5. 局限
  6. 参见

定义

Protostuff 是一个 Java 序列化库,同时包含 proto 编译器与代码生成器,其项目定位是「基于谷歌 Protocol Buffers 的序列化方案」,并在其基础上补充了额外功能与更简便的用法。[4] 它由 protostuff-api、protostuff-core、protostuff-runtime、protostuff-collectionschema 等多个模块组成,用户可按需引入其中一部分。[5]

与只提供二进制编解码的库不同,Protostuff 内置了对模式演进的支持,即在字段增删之后仍能保持前后版本之间的兼容,并支持对消息做校验。[3] 它既可以按照 .proto 文件生成 Java 类,也可以不写 .proto 而直接对已有的 POJO 做序列化,后者由 protostuff-runtime 模块实现。[6]

原理

Protostuff 的编解码沿用 Protocol Buffers 的线上格式(wire format):每个字段先写入字段编号与线类型,再写入取值,整数采用变长整数(Varint)压缩编码,字符串先写 UTF-8 字节长度再写内容。[5] 序列化过程中,Schema 对象负责描述目标类型的字段列表以及每个字段的读写逻辑,由 ProtostuffIOUtil 驱动输出到缓冲区。[4]

无模式序列化的关键在于 RuntimeSchema:它在运行时为目标类生成并缓存 Schema 元数据,从而无需预先编写和编译 IDL。生成后的 Schema 会被缓存复用,重复调用获取同一类的 Schema 开销很小。[6] 在未使用 @Tag 注解时,字段编号按字段在类中的声明顺序自上而下分配,因此这种顺序在部分虚拟机上并不被保证。[6]

按运行时开销从低到高,运行时 Schema 分为 3 类:静态 Schema 用于字段为具体类型的场合,不附带额外元数据因而最紧凑;DerivativeSchema 用于字段声明为抽象类的场合,需要额外写入类型元数据;ObjectSchema(动态)用于字段类型为 Object、接口、数组、未指定泛型的集合或过于复杂的类型,会在序列化时包含全部必要元数据。[6]

发展历程

Protostuff 的 1.0.0.M0 版本于 2009 年 10 月 24 日发布,该版本包含面向 json、numeric_json、gwt_json、gwt_numeric_json 的代码生成器、用于快速起步的 Maven 原型,以及用于与 protobuf 对比的基准测试模块。[7] 项目早期以 com.dyuproject.protostuff 为 Maven 坐标,作者为 David Yu,1.0.0 版本自 2011 年 6 月 7 日起进入中央仓库。[8]

1.0.5 版本起支持在字段上使用 @Tag 注解显式指定字段编号,1.0.7 版本起 @Tag 支持别名,用于在 json、xml、yaml 等文本格式中覆盖原字段名。[6] 1.0.x 分支后续由单独的仓库维护并持续打补丁,1.0.12、1.0.13 等版本发布于 2016 年。[9] 之后项目改用 io.protostuff 坐标,1.7.4 于 2021 年 4 月 30 日发布,1.8.0 于 2022 年 3 月 12 日发布,成为 33 个已发布版本中的最新版本。[10][2]

应用

Protostuff 的典型用途有两类:作为远程调用(RPC)中的消息编解码层,以及作为数据存储或缓存中的存储格式。[4] 在 Java 生态中,它被用于把对象写入字节流后再存入 Redis、Kafka 等中间件或缓存系统。[11]

在分布式服务框架中,它可以作为序列化协议接入。Apache Dubbo 默认使用 Hessian2 序列化,有公开研究通过扩展 Dubbo 的 Serialization、ObjectInput、ObjectOutput 等接口,把 Protostuff 作为可选序列化方案接入,并与之对比传输性能。[12] 在第三方库中,Apache Cayenne 曾以 Protostuff 实现其远程对象持久化(ROP)的序列化服务。[13]

由于兼容 protobuf 线上格式,Protostuff 可以把对象序列化为标准 protobuf 字节流,从而在跨语言环境下由其他语言的 protobuf 实现解读。[11] 按照 protobuf 的配置,它也可以把对象序列化为 json、yaml、xml 等文本格式。[14]

局限

使用 protostuff-runtime 时,反序列化只负责把字段值拷贝进已有对象,不负责创建对象实例,因此目标类必须提供默认构造函数。[14] 在未使用 @Tag 注解的情况下,字段编号取决于声明顺序,字段顺序需要保持一致,这给字段变更带来不便;并且部分非 Sun 虚拟机(尤其 dalvik)并不保证该顺序。[14][6] 不使用 @Tag 时,前后兼容只能依靠「仅在末尾追加」的方式实现,删除字段需要标注 @Deprecated,排除字段需要使用 transient 关键字。[6]

在数据类型变更上也存在限制:已有数据的情况下增删泛型信息会导致反序列化失败;int 与 long 之间可以互相变更且兼容所有支持的格式,而 String 与 byte[]、ByteString 之间可以互转,但在 json、xml、yaml 等文本格式下不兼容。[6] 此外,空集合在反序列化后可能变为 null。[14]

对象图序列化也有边界:序列化或反序列化根消息时,其嵌套消息中不应包含对根消息的引用;若集合字段可能形成环状引用,需要通过系统属性把集合字段当作独立消息处理。[15] 在性能对比中,Protostuff 的运行时方案在文档与学习曲线、引入成本与可维护性等维度的评分仅次于 Kryo,并未在所有测试项中领先。[16]

参见

  • Protocol Buffers —— Protostuff 的数据格式与编码规则所依据的谷歌序列化方案。

  • Kryo —— 同为 Java 的无模式二进制序列化库,常与 Protostuff 在性能上作对比。

  • Apache Dubbo —— 可接入 Protostuff 作为可选序列化协议的分布式服务框架。

  • 序列化 —— Protostuff 所实现的把对象状态转换为字节流的一般过程。

  • RPC —— Protostuff 的主要应用场景之一,即远程调用中的消息编解码。

  • Apache Cayenne —— 曾采用 Protostuff 实现其远程对象持久化的序列化服务。

参考资料

  1. google.com 上的网页 [引用日期2026-10-14]
  2. ecosyste.ms 上的网页 [引用日期2026-10-14]
  3. protostuff [引用日期2026-10-14]
  4. protostuff [引用日期2026-10-14]
  5. protostuff docs [引用日期2026-10-14]
  6. Runtime Schema [引用日期2026-10-14]
  7. protostuff-changelog [引用日期2026-10-14]
  8. files [引用日期2026-10-14]
  9. dyu/protostuff-1.0.x: Legacy version · GitHub [引用日期2026-10-14]
  10. io.protostuff:protostuff-core [引用日期2026-10-14]
  11. Protostuff无模式POJO序列化快速入门指南 [引用日期2026-10-14]
  12. 第9卷 第2期 [引用日期2026-10-14]
  13. CAY-2083 [引用日期2026-10-14]
  14. spring-boot-starter-grpc 不同序列化方式性能测试及选型 [引用日期2026-10-14]
  15. Serializing Object Graphs [引用日期2026-10-14]
  16. Morschel-Scientific-Thesis-Practical-Semester-public-1(PDF) [引用日期2026-10-14]
词条评价
词条统计

浏览次数:3 次

阅读量:1 次 · 阅读完成量:0 次

最近更新:2026-10-13T19:25:55Z

历史版本

本条目引用的词条
Protocol Buffers Schema Kryo Apache Dubbo 序列化 RPC Apache Cayenne