Въведение в Kryo

1. Общ преглед

Kryo е рамка за сериализация на Java с фокус върху скоростта, ефективността и лесен за използване API.

В тази статия ще разгледаме ключовите характеристики на рамката на Kryo и ще приложим примери, за да покажем нейните възможности.

2. Зависимост на Maven

Първото нещо, което трябва да направим, е да добавим зависимостта kryo към нашия pom.xml :

 com.esotericsoftware kryo 4.0.1 

Най-новата версия на този артефакт може да бъде намерена в Maven Central.

3. Основи на Kryo

Нека започнем, като разгледаме как работи Kryo и как можем да сериализираме и десериализираме обекти с него.

3.1. Въведение

Рамката осигурява клас Kryo като основна входна точка за цялата му функционалност.

Този клас организира процеса на сериализация и съпоставя класовете на екземпляри на сериализатора, които обработват подробностите за преобразуване на графика на обект в байтово представяне.

След като байтовете са готови, те се записват в поток с помощта на изходен обект. По този начин те могат да се съхраняват във файл, база данни или да се предават по мрежата.

По-късно, когато обектът е необходим, входен екземпляр се използва, за да прочете тези байтове и да ги декодира в Java обекти.

3.2. Сериализиране на обекти

Преди да се потопим в примери, нека първо създадем полезен метод за инициализиране на някои променливи, които ще използваме за всеки тест в тази статия:

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

Сега можем да разгледаме колко лесно е да пишете и четете обект с помощта на 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"); }

Забележете извикването на метода close () . Това е необходимо, тъй като класовете Output и Input наследяват съответно от OutputStream и InputStream .

Сериализирането на множество обекти е също толкова лесно:

@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. Сериализатори

В този раздел ще покажем кои сериализатори вече са налични и след това ще създадем наши собствени.

4.1. Сериализатори по подразбиране

Когато Kryo сериализира обект, той създава екземпляр на предварително регистриран клас на сериализатора, за да извърши преобразуването в байтове. Те се наричат ​​сериализатори по подразбиране и могат да бъдат използвани без настройка от наша страна.

Библиотеката вече предлага няколко такива сериализатори, които обработват примитиви, списъци, карти, изброявания и др. Ако не е намерен сериализатор за даден клас, тогава се използва FieldSerializer , който може да обработва почти всеки тип обект.

Нека да видим как изглежда това. Първо, нека създадем клас Person :

public class Person { private String name = "John Doe"; private int age = 18; private Date birthDate = new Date(933191282821L); // standard constructors, getters, and setters }

Сега, нека напишем обект от този клас и след това го прочетем обратно:

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

Забележете, че не трябваше да посочваме нищо, за да сериализираме обект Person, тъй като FieldSerializer се създава автоматично за нас.

4.2. Персонализирани сериализатори

Ако се нуждаем от повече контрол върху процеса на сериализация, имаме две възможности; можем да напишем собствен клас Serializer и да го регистрираме в Kryo или да оставим класа да се справи сам със сериализацията.

За да демонстрираме първата опция, нека създадем клас, който разширява Serializer :

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

Сега нека го поставим на тест:

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

Забележете, че възрастовото поле е равно на 18, въпреки че предварително сме го задали на 0.

Можем също така да използвате @DefaultSerializer анотацията към нека Kryo знаем, че искате да използвате PersonSerializer всеки път, когато тя трябва да се справи с Лице обект. Това помага да се избегне извикването на метода register () :

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

За втората опция, нека модифицираме нашия клас Person, за да разширим 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, използвайки JavaSerializer . Това изисква класът да изпълнява интерфейса за сериализиране както обикновено.

Ето пример, който използва гореспоменатия сериализатор:

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. Заключение

В този урок разгледахме най-забележителните характеристики на библиотеката Kryo.

Сериализирахме множество прости обекти и използвахме класа FieldSerializer, за да се справим с персонализиран. Също така създадохме персонализиран сериализатор и демонстрирахме как да се върнем към стандартния механизъм за сериализация на Java, ако е необходимо.

Както винаги, пълният изходен код за тази статия може да бъде намерен в Github.