kryo浅析

本文深入剖析Kryo,一种快速且高效的Java对象图序列化框架。Kryo使用字节码生成机制,无需实现Serializable接口,支持线程局部变量及池技术优化。文章通过实例演示了如何使用Kryo进行序列化和反序列化,并介绍了其依赖管理、性能优化及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

kryo浅析

简介

Kryo is a fast and efficient object graph serialization framework for Java. The goals of the project are speed, efficiency, and an easy to use API. The project is useful any time objects need to be persisted, whether to a file, database, or over the network.
https://github.com/EsotericSoftware/kryo

总结点

  1. 其使用了字节码生成机制(底层依赖了 ASM 库)
  2. 必须包含无参构造器
  3. 不需要实现Serializable接口
  4. Kryo是线程不安全的,意味着每当需要序列化和反序列化时都需要实例化一次,或者借助ThreadLocal来维护以保证其线程安全。
  5. 使用 transient 关键字标记的字段不参与序列化

简单实践

maven依赖

        <dependency>
            <groupId>com.esotericsoftware</groupId>
            <artifactId>kryo</artifactId>
            <!--<artifactId>kryo-shaded</artifactId>-->
            <version>4.0.2</version>
        </dependency>
@Data
public class User2 {

    private Long id;
    private String name;
    private Date date;
    private transient String str;
}
package morning.cat.study.kryo;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.pool.KryoPool;
import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.concurrent.ArrayBlockingQueue;

public class KryoSerializableTest {

    @Test
    public void test() throws IOException {
        // 序列化
        Kryo kryo = new Kryo();
        Output output = new Output(new FileOutputStream("kryo.bin"));
        kryo.writeObject(output, getUser());
        output.close();
    }

    @Test
    public void test2() throws IOException {
        // 反序列化
        Kryo kryo = new Kryo();
        Input input = new Input(new FileInputStream("kryo.bin"));
        User2 user = kryo.readObject(input, User2.class);
        System.out.println(user);
    }

    private User2 getUser() {
        User2 user = new User2();
        user.setId(System.currentTimeMillis());
        user.setName("Kryo_" + System.currentTimeMillis());
        user.setDate(Calendar.getInstance().getTime());
        user.setStr("transient 关键字标记 不参与序列化");
        System.out.println(user);
        return user;
    }

    private static final ThreadLocal<Kryo> kryos =
            new ThreadLocal<Kryo>() {
                @Override
                protected Kryo initialValue() {
                    Kryo kryo = new Kryo();
                    return kryo;
                }
            };

    @Test
    public void test3() throws FileNotFoundException {

        String fileName = "kryo_test3_3.bin";

        // ThreadLocal 方式
        Kryo kryo = kryos.get();
        kryo.setRegistrationRequired(false);//关闭注册行为
        kryo.setReferences(true);//支持循环引用
        Output output = new Output(new FileOutputStream(fileName));
        kryo.writeClassAndObject(output, getUser());
        output.close();

        Input input = new Input(new FileInputStream(fileName));
        Object object = kryo.readClassAndObject(input);
        if (object instanceof User2) {
            User2 user = (User2) object;
            System.out.println(user);
        }
    }


    @Test
    public void test4() {
        // 池技术
        KryoPool kryoPool = new KryoPool.Builder(() -> new Kryo()).queue(new ArrayBlockingQueue<>(20)).build();
        Kryo kryo = kryoPool.borrow();


        kryoPool.release(kryo);
    }


}

附录

参考文档:
http://www.iocoder.cn/RPC/laoxu/rpc-serialize-1/?geekbook

https://github.com/EsotericSoftware/kryo

### Kryo序列化的使用方法 Kryo 是一种高效的 Java 序列化框架,提供了快速的对象序列化和反序列化功能。以下是关于如何使用 Kryo 进行反序列化的详细介绍。 #### 1. 初始化 Kryo 实例 由于 Kryo 不是线程安全的,在多线程环境中可以通过 `ThreadLocal` 来管理多个独立的 Kryo 实例[^1]。 ```java private static final ThreadLocal<Kryo> kryos = new ThreadLocal<Kryo>() { @Override protected Kryo initialValue() { Kryo kryo = new Kryo(); // 配置 Kryo 实例并注册类 kryo.register(MyClass.class); return kryo; } }; ``` #### 2. 创建 Input 对象用于读取数据流 在反序列化过程中,需要创建一个 `Input` 对象来处理输入字节流。这个对象可以从文件、网络或其他来源中读取数据。 ```java // 假设我们有一个 InputStream 数据源 InputStream inputStream = new FileInputStream("serializedData.dat"); Input input = new Input(inputStream); try { // 获取当前线程绑定的 Kryo 实例 Kryo kryo = kryos.get(); // 调用 readObject 方法完成反序列化 MyClass deserializedObject = kryo.readObject(input, MyClass.class); } finally { // 关闭资源以释放内存 input.close(); } ``` #### 3. 类型注册的重要性 为了避免运行时抛出 `"KryoException: Encountered unregistered class ID"` 的错误,必须提前调用 `kryo.register()` 将目标类及其可能使用的子类全部注册到 Kryo 中[^2]。这样可以确保每种类型的唯一整数标识符被分配给它,从而提高效率并减少元数据大小。 #### 4. 处理复杂场景下的问题 如果项目涉及大量动态加载或第三方库,则需特别注意以下几点: - **自定义序列器**:对于某些特殊的数据结构(如集合类型),建议实现自己的 `Serializer` 并将其关联至对应实体上[^5]; - **兼容性考虑**:版本更新可能导致字段变更等问题,因此应测试不同环境间互操作能力; --- ### 解决反序列化过程中的常见问题 | **问题描述** | **原因分析** | **解决方案** | |--------------|--------------|--------------| | 出现未注册类别ID异常 (`Encountered unregistered class ID`) | 如果尝试解析未经预先声明的新种类别的实例将会触发此状况 | 如上述提到那样显式添加所需分类进入登记表单即可消除此类警告消息 | | 性能低下 | 缺乏优化措施比如重复构建短命对象 | 利用池技术重用已存在的组件而不是频繁新建它们 | --- ### 示例代码展示完整的流程 下面给出一段综合性的例子演示整个从配置初始化到最后一步恢复原始状态的操作链路: ```java import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.Input; import java.io.FileInputStream; import java.io.InputStream; public class Main { private static final ThreadLocal<Kryo> kryos = new ThreadLocal<Kryo>() { @Override protected Kryo initialValue() { Kryo kryo = new Kryo(); kryo.register(MyClass.class); // 注册要序列化的类 return kryo; } }; public static void main(String[] args) throws Exception { try (InputStream is = new FileInputStream("data.bin")) { Input input = new Input(is); Kryo kryoInstance = kryos.get(); MyClass obj = kryoInstance.readObject(input, MyClass.class); System.out.println(obj.toString()); } } } class MyClass implements Serializable{ String name; @Override public String toString(){ return "MyClass{name='" +name+"'}"; } } ``` [^3][^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值