1. 概述

Kryo 是一个专注于高性能、高效率的 Java 序列化框架,同时提供了简洁易用的 API。

本文将深入探讨 Kryo 框架的核心特性,并通过实际代码示例展示其强大功能。

2. Maven 依赖

首先需要在 pom.xml 中添加 Kryo 依赖:

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>4.0.1</version>
</dependency>

最新版本可在 Maven Central 查询。

3. Kryo 基础

让我们先了解 Kryo 的工作原理,以及如何用它进行对象序列化和反序列化。

3.1 核心机制

框架的核心是 Kryo 类,它是所有功能的入口点。该类负责:

  • ✅ 协调整个序列化流程
  • ✅ 将类映射到 Serializer 实例
  • ✅ 通过 Serializer 将对象图转换为字节流

序列化后的字节通过 Output 对象写入流,可存储到文件、数据库或网络传输。反序列化时,使用 Input 对象读取字节并解码为 Java 对象。

3.2 对象序列化

先创建测试初始化方法:

@Before
public void init() {
    kryo = new Kryo();
    output = new Output(new FileOutputStream("file.dat"));
    input = new Input(new FileInputStream("file.dat"));
}

单对象序列化简单粗暴:

@Test
public void givenObject_whenSerializing_thenReadCorrectly() {
    Object someObject = "Some string";

    kryo.writeClassAndObject(output, someObject);
    output.close();

    Object theObject = kryo.readClassAndObject(input);
    input.close();

    assertEquals(theObject, "Some string");
}

⚠️ 注意:必须调用 close() 方法,因为 OutputInput 分别继承自 OutputStreamInputStream

多对象序列化同样简单:

@Test
public void givenObjects_whenSerializing_thenReadCorrectly() {
    String someString = "Multiple Objects";
    Date someDate = new Date(915170400000L);

    kryo.writeObject(output, someString);
    kryo.writeObject(output, someDate);
    output.close();

    String readString = kryo.readObject(input, String.class);
    Date readDate = kryo.readObject(input, Date.class);
    input.close();

    assertEquals(readString, "Multiple Objects");
    assertEquals(readDate.getTime(), 915170400000L);
}

✅ 优势:通过指定 readObject() 的目标类,避免了类型转换。

4. 序列化器

本节介绍 Kryo 内置的序列化器,以及如何自定义序列化器。

4.1 默认序列化器

Kryo 序列化对象时,会自动创建已注册的 Serializer 实例。这些默认序列化器无需额外配置即可使用。

框架内置了处理以下类型的序列化器:

  • ✅ 基本数据类型
  • ✅ 集合(List/Map)
  • ✅ 枚举
  • ✅ 其他常见类型

当找不到匹配的序列化器时,Kryo 会使用 FieldSerializer,它能处理几乎所有类型的对象。

示例: 创建 Person 类:

public class Person {
    private String name = "John Doe";
    private int age = 18;
    private Date birthDate = new Date(933191282821L);

    // 标准构造器、getter和setter
}

直接序列化 Person 对象:

@Test
public void givenPerson_whenSerializing_thenReadCorrectly() {
    Person person = new Person();

    kryo.writeObject(output, person);
    output.close();

    Person readPerson = kryo.readObject(input, Person.class);
    input.close();

    assertEquals(readPerson.getName(), "John Doe");
}

✅ 无需任何配置,Kryo 自动为 Person 生成了 FieldSerializer

4.2 自定义序列化器

当需要更精细的控制时,有两种方案:

  1. 创建自定义 Serializer
  2. 让类自身实现序列化逻辑

方案一:自定义序列化器类

public class PersonSerializer extends Serializer<Person> {

    public void write(Kryo kryo, Output output, Person object) {
        output.writeString(object.getName());
        output.writeLong(object.getBirthDate().getTime());
    }

    public Person read(Kryo kryo, Input input, Class<Person> type) {
        Person person = new Person();
        person.setName(input.readString());
        long birthDate = input.readLong();
        person.setBirthDate(new Date(birthDate));
        person.setAge(calculateAge(birthDate));
        return person;
    }

    private int calculateAge(long birthDate) {
        // 自定义计算逻辑
        return 18;
    }
}

测试自定义序列化器:

@Test
public void givenPerson_whenUsingCustomSerializer_thenReadCorrectly() {
    Person person = new Person();
    person.setAge(0); // 初始值会被覆盖
    
    kryo.register(Person.class, new PersonSerializer());
    kryo.writeObject(output, person);
    output.close();

    Person readPerson = kryo.readObject(input, Person.class);
    input.close();

    assertEquals(readPerson.getName(), "John Doe");
    assertEquals(readPerson.getAge(), 18); // 验证自定义逻辑生效
}

✅ 使用 @DefaultSerializer 注解可避免手动注册:

@DefaultSerializer(PersonSerializer.class)
public class Person implements KryoSerializable {
    // ...
}

方案二:实现 KryoSerializable 接口

public class Person implements KryoSerializable {
    // ...

    public void write(Kryo kryo, Output output) {
        output.writeString(name);
        // 其他字段...
    }

    public void read(Kryo kryo, Input input) {
        name = input.readString();
        // 其他字段...
    }
}

4.3 Java 序列化器

极少数情况下 Kryo 无法序列化某个类时,可回退到标准 Java 序列化机制:

  1. 类需实现 Serializable 接口
  2. 使用 JavaSerializer 处理

示例:

public class ComplexObject implements Serializable {
    private String name = "Bael";
    
    // 标准getter和setter
}
@Test
public void givenJavaSerializable_whenSerializing_thenReadCorrectly() {
    ComplexClass complexObject = new ComplexClass();
    kryo.register(ComplexClass.class, new JavaSerializer());

    kryo.writeObject(output, complexObject);
    output.close();

    ComplexClass readComplexObject = kryo.readObject(input, ComplexClass.class);
    input.close();

    assertEquals(readComplexObject.getName(), "Bael");
}

⚠️ 踩坑提示:Java 序列化性能较差,仅作为最后备选方案。

5. 总结

本文深入探讨了 Kryo 框架的核心特性:

  • ✅ 序列化多种简单对象
  • ✅ 使用 FieldSerializer 处理自定义类
  • ✅ 创建自定义序列化器
  • ✅ 回退到 Java 标准序列化机制

完整源代码可在 GitHub 获取。


原始标题:Introduction To Kryo

» 下一篇: Jooby 框架介绍