Java 序列化指南
Apache Fory™ 提供极速的 Java 对象序列化,基于 JIT 编译和零拷贝技术。当只需要 Java 对象序列化时,这种模式相比跨语言对象图序列化提供更好的性能。
特性
高性能
- JIT 代码生成:高度可扩展的 JIT 框架在运行时使用异步多线程编译生成序列化器代码,通过以下方式提供 20-170 倍的加速:
- 内联变量以减少内存访问
- 内联方法调用以消除虚拟分派开销
- 最小化条件分支
- 消除哈希查找
- 零拷贝:直接内存访问,无中间缓冲区拷贝;行格式支持随机访问和部分序列化
- 变长编码:对整数和长整型进行优化压缩
- 元数据共享:缓存的类元数据减少冗余类型信息
- SIMD 加速:支持 Java Vector API 用于数组操作(Java 16+)
即插即用替代
- 100% JDK 序列化兼容:支持
writeObject/readObject/writeReplace/readResolve/readObjectNoData/Externalizable - Java 8-24 支持:适用于所有现代 Java 版本,包括 Java 17+ 的 record
- GraalVM Native Image:支持 AOT 编译,无需反射配置
高级特性
- 引用跟踪:自动处理共享引用和循环引用
- Schema 演化:类 schema 变更的前向/后向兼容性
- 多态性:完全支持继承层次结构和接口
- 深拷贝:高效深度克隆复杂对象图并保留引用
- 安全性:类注册和可配置的反序列化策略
快速开始
注意,Fory 的创建成本不低,应该在多次序列化之间复用 Fory 实例,而不是每次都创建。你应该将 Fory 作为静态全局变量,或者某个单例对象或有限对象的实例变量。
单线程使用
import java.util.List;
import java.util.Arrays;
import org.apache.fory.*;
import org.apache.fory.config.*;
public class Example {
public static void main(String[] args) {
SomeClass object = new SomeClass();
// 注意 Fory 实例应该在多次不同对象的序列化之间复用。
Fory fory = Fory.builder().withLanguage(Language.JAVA)
.requireClassRegistration(true)
.build();
// 注册类型可以减少类名序列化开销,但不是必须的。
// 如果启用了类注册,所有自定义类型都必须注册。
// 如果未指定 id,注册顺序必须一致
fory.register(SomeClass.class);
byte[] bytes = fory.serialize(object);
System.out.println(fory.deserialize(bytes));
}
}
多线程使用
import org.apache.fory.*;
import org.apache.fory.config.*;
public class Example {
public static void main(String[] args) {
SomeClass object = new SomeClass();
ThreadSafeFory fory = Fory.builder()
.withLanguage(Language.JAVA)
.buildThreadSafeFory();
fory.register(SomeClass.class, 1);
byte[] bytes = fory.serialize(object);
System.out.println(fory.deserialize(bytes));
}
}
Fory 实例复用模式
import org.apache.fory.*;
import org.apache.fory.config.*;
public class Example {
private static final ThreadSafeFory fory = Fory.builder()
.withLanguage(Language.JAVA)
.buildThreadSafeFory();
static {
fory.register(SomeClass.class, 1);
}
public static void main(String[] args) {
SomeClass object = new SomeClass();
byte[] bytes = fory.serialize(object);
System.out.println(fory.deserialize(bytes));
}
}
线程安全
Fory 提供两种线程安全运行时风格:
buildThreadSafeFory
这是默认选择。它会构建一个固定大小的共享 ThreadPoolFory,其大小为 4 * availableProcessors(),也是虚拟线程工作负载下的首选运行时:
ThreadSafeFory fory = Fory.builder()
.withLanguage(Language.JAVA)
.withRefTracking(false)
.withCompatibleMode(CompatibleMode.SCHEMA_CONSISTENT)
.withAsyncCompilation(true)
.buildThreadSafeFory();
更多细节请参见 虚拟线程。
ThreadLocalFory
仅当你明确希望为每个长期存在的平台线程分配一个 Fory 实例,或者无论 JDK 版本如何都要固定采用这种方式时,才使用 buildThreadLocalFory():
ThreadSafeFory fory = Fory.builder()
.withLanguage(Language.JAVA)
.buildThreadLocalFory();
fory.register(SomeClass.class, 1);
byte[] bytes = fory.serialize(object);
System.out.println(fory.deserialize(bytes));
buildThreadSafeForyPool
如果你希望显式指定固定共享池大小,请使用 buildThreadSafeForyPool(poolSize)。它会预先创建 poolSize 个 Fory 实例,把它们放在共享固定槽位中,然后让任意调用方通过与线程无关的快速路径借用实例。只有当池中所有实例都在使用时,调用才会阻塞;运行时不会按照线程身份缓存实例:
ThreadSafeFory fory = Fory.builder()
.withLanguage(Language.JAVA)
.withRefTracking(false)
.withCompatibleMode(CompatibleMode.SCHEMA_CONSISTENT)
.withAsyncCompilation(true)
.buildThreadSafeForyPool(poolSize);
Builder 方法
// 单线程 Fory
Fory fory = Fory.builder()
.withLanguage(Language.JAVA)
.withRefTracking(false)
.withCompatibleMode(CompatibleMode.SCHEMA_CONSISTENT)
.withAsyncCompilation(true)
.build();
// 线程安全 Fory(由 Fory 实例池支撑)
ThreadSafeFory fory = Fory.builder()
.withLanguage(Language.JAVA)
.withRefTracking(false)
.withCompatibleMode(CompatibleMode.SCHEMA_CONSISTENT)
.withAsyncCompilation(true)
.buildThreadSafeFory();
// 显式线程本地运行时
ThreadSafeFory threadLocalFory = Fory.builder()
.withLanguage(Language.JAVA)
.buildThreadLocalFory();