自定义序列化器
本页介绍如何为你的类型实现自定义序列化器。
基本自定义序列化器
在某些情况下,你可能想为你的类型实现序列化器,特别是对于使用 JDK writeObject/writeReplace/readObject/readResolve 自定义序列化的类,这非常低效。
例如,如果你不想调用以下 Foo#writeObject,你可以实现自定义序列化器:
class Foo {
public long f1;
private void writeObject(ObjectOutputStream s) throws IOException {
System.out.println(f1);
s.defaultWriteObject();
}
}
class FooSerializer extends Serializer<Foo> {
public FooSerializer(Fory fory) {
super(fory, Foo.class);
}
@Override
public void write(MemoryBuffer buffer, Foo value) {
buffer.writeInt64(value.f1);
}
@Override
public Foo read(MemoryBuffer buffer) {
Foo foo = new Foo();
foo.f1 = buffer.readInt64();
return foo;
}
}
注册序列化器
Fory fory = getFory();
fory.registerSerializer(Foo.class, new FooSerializer(fory));
除了注册序列化器,你还可以为类实现 java.io.Externalizable 来自定义序列化逻辑。这种类型将由 Fory 的 ExternalizableSerializer 序列化。
集合序列化器
在为自定义集合类型实现序列化器时,你必须扩展 CollectionSerializer 或 CollectionLikeSerializer。主要区别是 CollectionLikeSerializer 可以序列化具有类似集合结构但不是 Java Collection 子类型的类。
supportCodegenHook 参数
这个特殊参数控制序列化行为:
当为 true 时:
- 启用对集合元素的优化访问和 JIT 编译以获得更好的性能
- 直接序列化调用和内联集合项,无需动态序列化器分派成本
- 对标准集合类型有更好的性能
- 对大多数集合推荐
当为 false 时:
- 使用基于接口的元素访问和元素的动态序列化器分派(成本更高)
- 对自定义集合类型更灵活
- 当集合有特殊序列化需求时需要
- 处理复杂的集合实现
带 JIT 支持的集合序列化器
在实现带 JIT 支持的集合序列化器时,利用 Fory 现有的二进制格式和集合序列化基础设施:
public class CustomCollectionSerializer<T extends Collection> extends CollectionSerializer<T> {
public CustomCollectionSerializer(Fory fory, Class<T> cls) {
// supportCodegenHook 控制是否使用 JIT 编译
super(fory, cls, true);
}
@Override
public Collection onCollectionWrite(MemoryBuffer buffer, T value) {
// 写入集合大小
buffer.writeVarUint32Small7(value.size());
// 写入任何额外的集合元数据
return value;
}
@Override
public Collection newCollection(MemoryBuffer buffer) {
// 创建新的集合实例
Collection collection = super.newCollection(buffer);
// 读取并设置集合大小
int numElements = getAndClearNumElements();
setNumElements(numElements);
return collection;
}
}
注意:在实现 newCollection 时调用 setNumElements,让 Fory 知道要反序列化多少元素。
不带 JIT 的自定义集合序列化器
对于使用原始数组或有特殊要求的集合,实现禁用 JIT 的序列化器:
class IntList extends AbstractCollection<Integer> {
private final int[] elements;
private final int size;
public IntList(int size) {
this.elements = new int[size];
this.size = size;
}
public IntList(int[] elements, int size) {
this.elements = elements;
this.size = size;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < size;
}
@Override
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return elements[index++];
}
};
}
@Override
public int size() {
return size;
}
public int get(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException();
}
return elements[index];
}
public void set(int index, int value) {
if (index >= size) {
throw new IndexOutOfBoundsException();
}
elements[index] = value;
}
public int[] getElements() {
return elements;
}
}
class IntListSerializer extends CollectionLikeSerializer<IntList> {
public IntListSerializer(Fory fory) {
// 禁用 JIT,因为我们直接处理序列化
super(fory, IntList.class, false);
}
@Override
public void write(MemoryBuffer buffer, IntList value) {
// 写入大小
buffer.writeVarUint32Small7(value.size());
// 直接将元素写为原始 int
int[] elements = value.getElements();
for (int i = 0; i < value.size(); i++) {
buffer.writeVarInt32(elements[i]);
}
}
@Override
public IntList read(MemoryBuffer buffer) {
// 读取大小
int size = buffer.readVarUint32Small7();
// 创建数组并读取元素
int[] elements = new int[size];
for (int i = 0; i < size; i++) {
elements[i] = buffer.readVarInt32();
}
return new IntList(elements, size);
}
// 当禁用 JIT 时不使用这些方法
@Override
public Collection onCollectionWrite(MemoryBuffer buffer, IntList value) {
throw new UnsupportedOperationException();
}
@Override
public Collection newCollection(MemoryBuffer buffer) {
throw new UnsupportedOperationException();
}
@Override
public IntList onCollectionRead(Collection collection) {
throw new UnsupportedOperationException();
}
}
何时使用此方法:
- 处理原始类型
- 需要最大性能
- 想要最小化内存开销
- 有特殊的序列化需求
类集合类型序列化器
对于行为类似集合但不是标准 Java 集合的类型:
class CustomCollectionLike {
private final Object[] elements;
private final int size;
public CustomCollectionLike(int size) {
this.elements = new Object[size];
this.size = 0;
}
public CustomCollectionLike(Object[] elements, int size) {
this.elements = elements;
this.size = size;
}
public Object get(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException();
}
return elements[index];
}
public int size() {
return size;
}
public Object[] getElements() {
return elements;
}
}
class CollectionView extends AbstractCollection<Object> {
private final Object[] elements;
private final int size;
private int writeIndex;
public CollectionView(CustomCollectionLike collection) {
this.elements = collection.getElements();
this.size = collection.size();
}
public CollectionView(int size) {
this.size = size;
this.elements = new Object[size];
}
@Override
public Iterator<Object> iterator() {
return new Iterator<Object>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < size;
}
@Override
public Object next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return elements[index++];
}
};
}
@Override
public boolean add(Object element) {
if (writeIndex >= size) {
throw new IllegalStateException("Collection is full");
}
elements[writeIndex++] = element;
return true;
}
@Override
public int size() {
return size;
}
public Object[] getElements() {
return elements;
}
}
class CustomCollectionSerializer extends CollectionLikeSerializer<CustomCollectionLike> {
public CustomCollectionSerializer(Fory fory) {
super(fory, CustomCollectionLike.class, true);
}
@Override
public Collection onCollectionWrite(MemoryBuffer buffer, CustomCollectionLike value) {
buffer.writeVarUint32Small7(value.size());
return new CollectionView(value);
}
@Override
public Collection newCollection(MemoryBuffer buffer) {
int numElements = buffer.readVarUint32Small7();
setNumElements(numElements);
return new CollectionView(numElements);
}
@Override
public CustomCollectionLike onCollectionRead(Collection collection) {
CollectionView view = (CollectionView) collection;
return new CustomCollectionLike(view.getElements(), view.size());
}
}
Map 序列化器
在为自定义 Map 类型实现序列化器时,扩展 MapSerializer 或 MapLikeSerializer。主要区别是 MapLikeSerializer 可以序列化具有类似 map 结构但不是 Java Map 子类型的类。