入门
-
Kryo(github地址)是一个快速,高效的对象图序列化Java框架。该项目的目标是速度,效率和易于使用的API。无论何时需要将对象持久化到文件,数据库还是通过网络,该项目都非常有用。
-
Kryo还可以执行自动的深层和浅层复制/克隆。这是直接从对象复制到对象,而不是对象->字节->对象
-
依赖
compile group: 'com.esotericsoftware', name: 'kryo', version: '4.0.1'
-
由于其底层依赖于 ASM 技术,与 Spring 等框架可能会发生 ASM 依赖的版本冲突,所以提供了另外一个依赖以供解决此问题
compile group: 'com.esotericsoftware', name: 'kryo-shaded', version: '4.0.1'
-
简单操作
public class Person { private String username = "jannal"; private String password = "123"; ...省略getter setter... } @Test public void case1() throws FileNotFoundException { Kryo kryo = new Kryo(); Output output = new Output(new FileOutputStream("person.db")); Person person = new Person(); kryo.writeObject(output, person); output.close(); Input input = new Input(new FileInputStream("person.db")); person = kryo.readObject(input, Person.class); input.close(); assert "jannal".equals(person.getUsername()); }
读写方式
-
Kryo 共支持三种读写方式
-
如果类是已知的,并且对象不为null
kryo.writeObject(output, someObject); // ... SomeClass someObject = kryo.readObject(input, SomeClass.class);
-
如果类是已知的,并且对象可能为null
kryo.writeObjectOrNull(output, someObject); // ... SomeClass someObject = kryo.readObjectOrNull(input, SomeClass.class);
-
如果类的字节码未知,并且对象可能为 null
kryo.writeClassAndObject(output, object); // ... Object object = kryo.readClassAndObject(input); if (object instanceof SomeClass) { // ... }
API介绍
-
某些类无法由Kryo序列化时可以使用
//类实现了Serializable kryo.register(SomeClass.class, new JavaSerializer()); //类实现了Externalizable kryo.register(SomeClass.class, new ExternalizableSerializer());
-
自定义序列化处理器
@Test public void case3() throws FileNotFoundException { Kryo kryo = new Kryo(); kryo.register(Student.class, new StudentSerializer()); Output output = new Output(new FileOutputStream("student.db")); Student student = new Student("jannal"); kryo.writeObject(output, student); output.close(); Input input = new Input(new FileInputStream("student.db")); student = kryo.readObject(input, Student.class); input.close(); Assert.assertEquals("jannal", student.getName()); Assert.assertEquals("jannal", student.getPerson().getUsername()); } public class StudentSerializer extends Serializer<Student> { /** * 对象写入字节 */ @Override public void write(Kryo kryo, Output output, Student student) { output.writeString(student.getName()); output.writeString(student.getPerson().getUsername()); output.writeString(student.getPerson().getPassword()); } /** * 从字节中读取转换为对象 */ @Override public Student read(Kryo kryo, Input input, Class<Student> clazz) { String name = input.readString(); String username = input.readString(); String password = input.readString(); Student student = new Student(name); Person person = new Person(); person.setUsername(username); person.setPassword(password); student.setPerson(person); return student; } }
-
Kryo 支持对注册行为,当Kryo写出对象的实例时,需要写出一些东西来识别标识对象类,默认情况下使用类的权限定名称和写入对象的字节,使用类名效率不高,可以提前注册类的标识,使用可变长度int保存。反序列化期间,注册的类必须具有与序列化期间完全相同的ID
-
当ID为较小的正整数时,它们的写入效率最高。负ID无法有效地序列化。默认情况下原生类型、包装类型、字符串、void使用
0-9
.可以将Kryo#setRegistrationRequired
设置为true,在遇到任何未注册的类时引发异常,这样可以防止应用程序意外使用类名字符串。@Test public void testRegister() throws FileNotFoundException { Kryo kryo = new Kryo(); //id不能是负数 kryo.register(Person.class, 10); Output output = new Output(new FileOutputStream("person.db")); Person person = new Person(); kryo.writeObject(output, person); output.close(); Input input = new Input(new FileInputStream("person.db")); person = kryo.readObject(input, Person.class); input.close(); Assert.assertEquals("jannal", person.getUsername()); }
-
缺点
- Kryo 不支持 Bean 中增删字段
- 使用 Arrays.asList(); 创建的 List 对象,会引起序列化异常
- 不支持包含无参构造器类的反序列化
- Kryo 是线程不安全的,每当需要序列化和反序列化时都需要实例化一次或者通过ThreadLocal
kryo-serializers
-
使用第三方库对 Kryo 进行序列化类型的扩展kryo-serializers
compile group: 'de.javakaffee', name: 'kryo-serializers', version: '0.45'
-
手动注册
kryo.register( Arrays.asList( "" ).getClass(), new ArraysAsListSerializer() ); kryo.register( Collections.EMPTY_LIST.getClass(), new CollectionsEmptyListSerializer() ); kryo.register( Collections.EMPTY_MAP.getClass(), new CollectionsEmptyMapSerializer() ); kryo.register( Collections.EMPTY_SET.getClass(), new CollectionsEmptySetSerializer() ); kryo.register( Collections.singletonList( "" ).getClass(), new CollectionsSingletonListSerializer() ); kryo.register( Collections.singleton( "" ).getClass(), new CollectionsSingletonSetSerializer() ); kryo.register( Collections.singletonMap( "", "" ).getClass(), new CollectionsSingletonMapSerializer() ); kryo.register( GregorianCalendar.class, new GregorianCalendarSerializer() ); kryo.register( InvocationHandler.class, new JdkProxySerializer() ); UnmodifiableCollectionsSerializer.registerSerializers( kryo ); SynchronizedCollectionsSerializer.registerSerializers( kryo ); // custom serializers for non-jdk libs // register CGLibProxySerializer, works in combination with the appropriate action in handleUnregisteredClass (see below) kryo.register( CGLibProxySerializer.CGLibProxyMarker.class, new CGLibProxySerializer( kryo ) ); // dexx ListSerializer.registerSerializers( kryo ); MapSerializer.registerSerializers( kryo ); SetSerializer.registerSerializers( kryo ); // joda DateTime, LocalDate, LocalDateTime and LocalTime kryo.register( DateTime.class, new JodaDateTimeSerializer() ); kryo.register( LocalDate.class, new JodaLocalDateSerializer() ); kryo.register( LocalDateTime.class, new JodaLocalDateTimeSerializer() ); kryo.register( LocalDateTime.class, new JodaLocalTimeSerializer() ); // protobuf kryo.register( SampleProtoA.class, new ProtobufSerializer() ); // or override Kryo.getDefaultSerializer as shown below // wicket kryo.register( MiniMap.class, new MiniMapSerializer() ); // guava ImmutableList, ImmutableSet, ImmutableMap, ImmutableMultimap, ImmutableTable, ReverseList, UnmodifiableNavigableSet ImmutableListSerializer.registerSerializers( kryo ); ImmutableSetSerializer.registerSerializers( kryo ); ImmutableMapSerializer.registerSerializers( kryo ); ImmutableMultimapSerializer.registerSerializers( kryo ); ImmutableTableSerializer.registerSerializers( kryo ); ReverseListSerializer.registerSerializers( kryo ); UnmodifiableNavigableSetSerializer.registerSerializers( kryo ); // guava ArrayListMultimap, HashMultimap, LinkedHashMultimap, LinkedListMultimap, TreeMultimap, ArrayTable, HashBasedTable, TreeBasedTable ArrayListMultimapSerializer.registerSerializers( kryo ); HashMultimapSerializer.registerSerializers( kryo ); LinkedHashMultimapSerializer.registerSerializers( kryo ); LinkedListMultimapSerializer.registerSerializers( kryo ); TreeMultimapSerializer.registerSerializers( kryo ); ArrayTableSerializer.registerSerializers( kryo ); HashBasedTableSerializer.registerSerializers( kryo ); TreeBasedTableSerializer.registerSerializers( kryo );