사용자 도구

사이트 도구


java:kryo

Kryo - Java 직렬화(Serialization)

의존성

  • 의존성 설정시 asm 라이브러리 버전 충돌이 발생한다면 kryo 대신 kryo-shaded artifact를 사용한다. 이는 asm 라이브러리를 repackaging해서 사용한다.

기본 직렬화/역직렬화

public static final int BASE_FLAG = 0;
 
@Override
public CachedObject encode(Object o) {
    Kryo kryo = new Kryo();
 
    // maxBufferSize = -1 이면 무제한(actually Integer.MAX_VALUE)
    Output output = new Output(bufferSize, maxBufferSize);
    kryo.writeClassAndObject(output, o);
    byte[] bytes = output.toBytes();
 
    return new CachedObjectImpl(BASE_FLAG, bytes);
}
 
@Override
public Object decode(CachedObject data) {
    Kryo kryo = new Kryo();
 
    return kryo.readClassAndObject(new Input(data.getData()));
}
  • encode시에 maxBufferSize를 너무 작게 잡으면 대용랴 데이터를 인코딩할 수 없을 수 있다. 원하는 최대 데이터 크기에 맞게 잡아줘야한다.

서로 다른 버전의 Class 지원

  • 캐시된 클래스가 달라질 경우, 역직렬화시에 오류가 발생한다.
  • CompatibleFieldSerializer 를 사용하면 오류는 발생하지 않는다.
    Kryo kryo = new Kryo();
    kryo.setDefaultSerializer(CompatibleFieldSerializer.class);
  • 하지만 서버별로 객체는 생성했으나 필드에 값이 없는 경우가 발생할 수도 있다.

Hibernate LazyInitializationException with Kryo

org.hibernate.LazyInitializationException when de-serializing

  kryoSerializer = new Kryo() {
    @Override
    public Serializer<?> getDefaultSerializer( final Class type ) {
      if (AbstractPersistentCollection.class.isAssignableFrom( type )) {
        return new FieldSerializer( kryoSerializer, type );
      }
      return super.getDefaultSerializer( type );
    }
  }
 
// AbstractPersistentCollection is org.hibernate.collection.AbstractPersistentCollection. 
// 혹시 kryo.addDefaultSerializer() 사용할 수 있는지, 없다면 왜 안되는지 확인 필요.

Kryo Object Pool

Kryo 3.x 부터 Kryo Object Pool 기능이 생겨서 성능 향상에 도움이 될 수 있음.

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.pool.*;
 
KryoFactory factory = new KryoFactory() {
  public Kryo create () {
    Kryo kryo = new Kryo();
    // configure kryo instance, customize settings
    return kryo;
  }
};
// Build pool with SoftReferences enabled (optional)
KryoPool pool = new KryoPool.Builder(factory).softReferences().build();
Kryo kryo = pool.borrow();
// do s.th. with kryo here, and afterwards release it
pool.release(kryo);
 
// or use a callback to work with kryo - no need to borrow/release,
// that's done by `run`.
String value = pool.run(new KryoCallback() {
  public String execute(Kryo kryo) {
    return kryo.readObject(input, String.class);
  }
});

기본 생성자(No args constructor)가 없을 경우

  • 기본 생성자가 존재하지 않을 경우에는 객체를 생성하지 못해서 오류가 발생한다. 단, private 으로라도 존재하면 괜찮다.
  • 순수 Kryo만 사용할 때는 objenesis의 StdInstantiatorStrategy를 사용한다.
    Kryo kryo = new Kryo();
     
    // 먼저 기본 생성자로 객체 생성을 시도하고,
    // 실패시에 생성자 없이 객체 생성시도하는 설정.
    kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
    • Kryo.DefaultInstantiatorStrategy 일단, 기본 생성자로 생성시도,
    • 안 될 경우 StdInstantiatorStrategy 로 생성
  • Kryo 객체 대신 kryo-serializers 의 KryoReflectionFactorySupport를 사용하는 것도 가능 - Oracle JDK만 지원
    Kryo kryo = new KryoReflectionFactorySupport();

Enum

Kryo 기본적으로 Enum을 ordinal로 직렬화한다. 이 경우 Enum의 순서가 변경되면 문제가 발생한다. 3.0.3 버전 이후부터 EnumNameSerializer가 추가되었다. 이를 사용하면 이름 기반 직렬화를 한다.

kryo.addDefaultSerializer(Enum.class, EnumNameSerializer.class);
java/kryo.txt · 마지막으로 수정됨: 2016/01/08 20:20 저자 kwon37xi