Schema 演化
本页介绍 schema 演化、元数据共享以及处理不存在的类。
处理类 Schema 演化
在许多系统中,用于序列化的类的 schema 可能会随时间而改变。例如,类中的字段可能会被添加或删除。当序列化和反序列化过程使用不同版本的 jar 时,被反序列化的类的 schema 可能与序列化期间使用的不同。
默认模式:SCHEMA_CONSISTENT
默认情况下,Fory 使用 CompatibleMode.SCHEMA_CONSISTENT 模式序列化对象。此模式假设反序列化过程使用与序列化过程相同的类 schema,从而最小化有效负载开销。但是,如果存在 schema 不一致,反序列化将失败。
兼容模式
如果预期 schema 会发生变化,为了使反序列化成功(即 schema 前向/后向兼容性),用户必须配置 Fory 使用 CompatibleMode.COMPATIBLE。这可以使用 ForyBuilder#withCompatibleMode(CompatibleMode.COMPATIBLE) 方法完成。
在此兼容模式下,反序列化可以处理 schema 变更,如缺失或额外的字段,允许在序列化和反序列化过程具有不同类 schema 时也能成功。
Fory fory = Fory.builder()
.withCompatibleMode(CompatibleMode.COMPATIBLE)
.build();
byte[] bytes = fory.serialize(object);
System.out.println(fory.deserialize(bytes));
此兼容模式涉及将类元数据序列化到序列化输出中。尽管 Fory 使用复杂的压缩技术来最小化开销,但与类元数据相关联的仍有一些额外的空间成本。
元数据共享
为了进一步降低元数据成本,Fory 引入了类元数据共享机制,允许元数据只发送到反序列化过程一次。
Fory 支持在上下文(例如 TCP 连接)中的多次序列化之间共享类型元数据(类名、字段名、最终字段类型信息等)。此信息将在上下文中的第一次序列化期间发送到对等端。基于此元数据,对等端可以重建相同的反序列化器,这避免了为后续序列化传输元数据,并降低网络流量压力,同时自动支持类型前向/后向兼容性。
使用元数据共享
// Fory.builder()
// .withLanguage(Language.JAVA)
// .withRefTracking(false)
// // 在多次序列化之间共享元数据。
// .withMetaContextShare(true)
// 非线程安全 fory。
MetaContext context = xxx;
fory.getSerializationContext().setMetaContext(context);
byte[] bytes = fory.serialize(o);
// 非线程安全 fory。
MetaContext context = xxx;
fory.getSerializationContext().setMetaContext(context);
fory.deserialize(bytes);
线程安全元数据共享
// 线程安全 fory
fory.setClassLoader(beanA.getClass().getClassLoader());
byte[] serialized = fory.execute(
f -> {
f.getSerializationContext().setMetaContext(context);
return f.serialize(beanA);
}
);
// 线程安全 fory
fory.setClassLoader(beanA.getClass().getClassLoader());
Object newObj = fory.execute(
f -> {
f.getSerializationContext().setMetaContext(context);
return f.deserialize(serialized);
}
);
注意:MetaContext 不是线程安全的,不能在 Fory 实例或多个线程之间重用。在多线程情况下,必须为每个 Fory 实例创建单独的 MetaContext。
有关更多详细信息,请参阅 元数据共享规范。
反序列化不存在的类
Fory 支持反序列化不存在的类。此功能可以通过 ForyBuilder#deserializeNonexistentClass(true) 启用。
启用时,如果启用了元数据共享,Fory 将把此类型的反序列化数据存储在 Map 的延迟子类中。通过使用 Fory 实现的延迟映射,可以避免反序列化期间填充映射的重新平衡成本,从而进一步提高性能。
如果此数据被发送到另一个进程,并且该类在此过程中存在,则数据将被反序列化为此类型的对象,而不会丢失任何信息。
如果未启用元数据共享,新类数据将被跳过,并返回 NonexistentSkipClass 存根对象。