Introduction à Kryo

Introduction à Kryo

1. Vue d'ensemble

Kryo est un framework de sérialisation Java axé sur la vitesse, l'efficacité et une API conviviale.

Dans cet article, nous allons explorer les principales caractéristiques du framework Kryo et implémenter des exemples pour présenter ses capacités.

2. Dépendance Maven

La première chose que nous devons faire est d'ajouter la dépendancekryo à nospom.xml:


    com.esotericsoftware
    kryo
    4.0.1

La dernière version de cet artefact peut être trouvée surMaven Central.

3. Les bases de Kryo

Commençons par examiner le fonctionnement de Kryo et comment nous pouvons sérialiser et désérialiser des objets avec.

3.1. introduction

Le framework fournit la classeKryo comme point d'entrée principal pour toutes ses fonctionnalités.

Cette classe orchestre le processus de sérialisation et mappe les classes aux instancesSerializer qui gèrent les détails de la conversion du graphique d'un objet en une représentation octet.

Une fois que les octets sont prêts, ils sont écrits dans un flux à l’aide d’un objetOutput. De cette façon, ils peuvent être stockés dans un fichier, une base de données ou transmis sur le réseau.

Plus tard, lorsque l'objet est nécessaire, une instanceInput est utilisée pour lire ces octets et les décoder en objets Java.

3.2. Sérialiser des objets

Avant de plonger dans des exemples, commençons par créer une méthode utilitaire pour initialiser certaines variables que nous utiliserons pour chaque cas de test dans cet article:

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

Maintenant, nous pouvons voir à quel point il est facile d’écrire et de lire un objet en utilisant Kryo:

@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");
}

Notez l'appel à la méthodeclose(). Ceci est nécessaire car les classesOutput etInput héritent respectivement deOutputStream etInputStream.

La sérialisation de plusieurs objets est également simple:

@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);
}

Notez que nous transmettons la classe appropriée à la méthodereadObject(), cela rend notre code sans cast.

4. Sérialiseurs

Dans cette section, nous allons montrer quelsSerializers sont déjà disponibles, puis nous créerons les nôtres.

4.1. Sérialiseurs par défaut

Lorsque Kryo sérialise un objet, il crée une instance d'une classeSerializer précédemment enregistrée pour effectuer la conversion en octets. Celles-ci sont appelées sérialiseurs par défaut et peuvent être utilisées sans configuration de notre part.

La bibliothèque fournit déjà plusieurs sérialiseurs de ce type qui traitent des primitives, des listes, des cartes, des énumérations, etc. Si aucun sérialiseur n'est trouvé pour une classe donnée, alors unFieldSerializer est utilisé, qui peut gérer presque n'importe quel type d'objet.

Voyons à quoi cela ressemble. Tout d'abord, créons une classePerson:

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

    // standard constructors, getters, and setters
}

Maintenant, écrivons un objet de cette classe, puis relisons-le:

@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");
}

Notez que nous n’avons rien à spécifier pour sérialiser un objetPerson car unFieldSerializer est créé automatiquement pour nous.

4.2. Sérialiseurs personnalisés

Si nous avons besoin de plus de contrôle sur le processus de sérialisation, nous avons deux options; nous pouvons écrire notre propre classeSerializer et l'enregistrer avec Kryo ou laisser la classe gérer la sérialisation par elle-même.

Pour illustrer la première option, créons une classe qui étendSerializer:

public class PersonSerializer extends Serializer {

    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 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) {
        // Some custom logic
        return 18;
    }
}

Maintenant, mettons-le à l’essai:

@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);
}

Notez que le champage est égal à 18, même si nous l'avons défini précédemment à 0.

Nous pouvons également utiliser l'annotation@DefaultSerializer pour faire savoir à Kryo que nous voulons utiliser lesPersonSerializer chaque fois qu'il doit gérer un objetPerson. Cela permet d'éviter l'appel à la méthoderegister():

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

Pour la deuxième option, modifions notre classePerson pour étendre l'interfaceKryoSerializable:

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();
        // ...
    }
}

Comme le scénario de test de cette option est égal à un précédent, n’est pas inclus ici. Cependant, vous pouvez le trouver dans le code source de cet article.

4.3. Sérialiseur Java

Dans des cas sporadiques, Kryo ne pourra pas sérialiser une classe. Si cela se produit et que l’écriture d’un sérialiseur personnalisé n’est pas une option, nous pouvons utiliser le mécanisme de sérialisation Java standard en utilisant unJavaSerializer. Cela nécessite que la classe implémente l'interfaceSerializable comme d'habitude.

Voici un exemple qui utilise le sérialiseur susmentionné:

public class ComplexObject implements Serializable {
    private String name = "Bael";

    // standard getters and setters
}
@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");
}

5. Conclusion

Dans ce tutoriel, nous avons exploré les fonctionnalités les plus remarquables de la bibliothèque Kryo.

Nous avons sérialisé plusieurs objets simples et utilisé la classeFieldSerializer pour gérer un objet personnalisé. Nous avons également créé un sérialiseur personnalisé et montré comment revenir au mécanisme de sérialisation Java standard si nécessaire.

Comme toujours, le code source complet de cet article peut être trouvéover on Github.