zoukankan      html  css  js  c++  java
  • 序列化 — Kryo序列化

    一.Kryo介绍

    Kryo是一个快速且高效的针对Java对象序列化的框架。它的特点:

    1. 序列化的性能非常高
    2. 序列化结果体积较小
    3. 提供了简单易用的API

    Kryo序列化被很多开源项目使用,社区非常活跃,版本迭代也比较快。以下的重大项目中都在使用Kryo

    • Apache Hive
    • Apache Spark
    • Twitter's Chill
    • Storm
    • akka-kryo-serialization

    由此可见Kryo的确具有很大的优势。但是Kryo是针对Java Object的序列化,对于跨语言方面是不支持的,但是很多场景中比如RPC,Cache,Store场景中一般很少需要对跨语言的支持。因此,Kryo的适用场景也很不错。

    二.Kryo使用

    static void quickStart() throws FileNotFoundException {
        Kryo kryo = new Kryo();
        Output output = new Output(new FileOutputStream("file.bin"));
        SomeClass someObject = new SomeClass();
        someObject.setValue("this is someObject.");
        kryo.writeObject(output, someObject);
        output.close();
    
        Input input = new Input(new FileInputStream("file.bin"));
        SomeClass deSomeObject = kryo.readObject(input, SomeClass.class);
        input.close();
        
        Assert.assertEquals(someObject.getValue(), deSomeObject.getValue());
    }
    

    1.Kryo的IO

    Kryo致力以简单易用的API,序列化过程中主要核心有Kryo、Output、Input。

    Output和Input是Kryo的IO,他们支持以byte array或者stream的形式为序列化的dest和反序列化的source。当使用stream形式进行写出写入时,需要close这些Output和Input。

    写出时,当OutputDe buffer是满的时候,就会flush bytes到stream中。写入时,会从stream中获取bytes到Input buffer中,当填充满时,进行反序列化。

    2.Kryo的注册

    和很多其他的序列化框架一样,Kryo为了提供性能和减小序列化结果体积,提供注册的序列化对象类的方式。在注册时,会为该序列化类生成int ID,后续在序列化时使用int ID唯一标识该类型。

    注册的方式如下:

    kryo.register(SomeClass.class);
    

    或者

    kryo.register(SomeClass.class, 1);
    

    可以明确指定注册类的int ID,但是该ID必须大于等于0。如果不提供,内部将会使用int++的方式维护一个有序的int ID生成。

    3.Kryo的Serializers

    Kryo是序列化的框架,但是其具体的序列化逻辑并不是Kryo完成的,它提供了大量Serializer序列化器用于对相应的数据类型做序列化,以一种插件的方式集成进Kryo。比如Kryo支持大量数据类型的序列化

    • 布尔、byte、char、short、int、long、float、double
    • String、Collection
    • Calendar、Date、TimeZone
    • Enum、EnumSet

    等等...,Kryo对这些对象都提供相应的Serializer,一支持其特定的序列化方式。

    在Kryo中Serializer主要提供两个抽象方法供实现

    abstract public void write (Kryo kryo, Output output, T object);
    
    abstract public T read (Kryo kryo, Input input, Class<T> type);
    

    用户可以根据需要自行扩展实现自己的序列化器Serializer。序列化器需要注册到Kryo,让Kryo用于处理特定类型的对象的序列化:

    kryo.register(SomeClass.class, new SomeSerializer());
    

    以上的大量的基本类型的序列化器由Kryo默认提供,并在初始化Kryo时已经注册。

    但是大多数场景还是一些业务对象的序列化,并不是以上的默认类型。不可能每次序列化对象时,都需要编写相应的Serializer。对于这种场景,Kryo提供了默认的通用Serializer - FieldSerializer。大多数类的序列化都是使用该序列化器,它对public、protected、package的field使用bytecode genreation,对于private使用setAccessible和反射。

    当然Kryo还提供了Java Serialization的Serializer实现JavaSerializer,但是这样该类就需要遵循Java规范,实现Serializable接口。

    4.引用

    Kryo允许多引用和循环引用,虽然开销很小,对此Kryo提供配置接口禁用以节省空间:

     Kryo kryo = new Kryo();
     kryo.setReferences(false);
    

    5.Kryo的读和写的方式

    Kryo提供三种读写对象的方式

    如果序列化的对象类型未知并且可能为空:

    kryo.writeClassAndObject(output, object);
    // ...
    Object object = kryo.readClassAndObject(input);
    if (object instanceof SomeClass) {
       // ...
    }
    

    如果对象类型已知并且可能为空:

    kryo.writeObjectOrNull(output, someObject);
    // ...
    SomeClass someObject = kryo.readObjectOrNull(input, SomeClass.class);
    

    如果对象类型已知并且不可能为空:

    kryo.writeObject(output, someObject);
    // ...
    SomeClass someObject = kryo.readObject(input, SomeClass.class);
    

    #### 三.Kryo的弊端

    前文中介绍大多数类的序列化基本上使用了FieldSerializer,该Serializer不支持对序列化对象类的field的Add、Rename、Remove操作,即如果更改了对象的字段,然后再从更改前序列化的bytes中反序列化,将会出错。

    当然如果想得到Add、Remove等操作的支持,可以使用FieldSerializer的其他扩展,如TaggedFieldSerializer、VersionFieldSerializer等等

    参考

    kryo

  • 相关阅读:
    day5-装饰器的正确打开方式------------->懒
    python_day5--->递归函数,二分法查找
    day4_生成器yield
    day4_迭代器
    day4_装饰器
    day4_函数嵌套和闭包以及作用域
    this作用域,改变作用域的方法
    $.ajax传数据.php
    ul标签的引用
    URL
  • 原文地址:https://www.cnblogs.com/lxyit/p/12511645.html
Copyright © 2011-2022 走看看