kryo的簡單使用

前言:kryo是個高效的java序列化/反序列化庫,目前Twitter、yahoo、Apache、strom等等在使用該技術,比如Apache的spark、hive等大數據領域用的較多。

爲什麼使用kryo而不是其他?
因爲性能足夠好。比kyro更高效的序列化庫就只有google的protobuf了(而且兩者性能很接近),protobuf有個缺點就是要傳輸的每一個類的結構都要生成對應的proto文件(也可以都放在同一個proto文件中,如果考慮到擴展性的話,不建議放在一個proto文件中),如果某個類發生修改,還得重新生成該類對應的proto文件;另外考慮到項目中用的全部是java技術棧,不存在不同編程語言間的兼容性問題,因此最終採用了kryo作爲序列化庫。

使用場景:(數據交換或數據持久化)比如使用kryo把對象序列化成字節數組發送給消息隊列或者放到redis等nosql中等等應用場景。

注意:由於kryo不是線程安全的,針對多線程情況下的使用,要對kryo進行一個簡單的封裝設計,從而可以多線程安全的使用序列化和反序列化

序列化和反序列化接口設計
/**
 * 序列化工具(程序調用該接口來實現obj<->byte[]之間的序列化/反序列化)
 * @author eguid
 *
 */
public interface Serializer{
    
    /**
     * 序列化
     * @param t
     * @param bytes
     */
    public void serialize(Object t,byte[] bytes);
    
    /**
     * 序列化
     * @param obj
     * @param bytes
     * @param offset
     * @param count
     */
    public void serialize(Object obj, byte[] bytes, int offset, int count);
    
    /**
     * 反序列化
     * @param bytes -字節數組
     * @return T<T>
     */
    public <T>T deserialize(byte[] bytes);
    
 
    /**
     * 反序列化
     * @param bytes
     * @param offset
     * @param count
     * @return
     */
    public <T>T deserialize(byte[] bytes, int offset, int count);
 
}
使用kryo實現上面的接口
/**
 * 基於kyro的序列化/反序列化工具
 * 
 * @author eguid
 *
 */
public class kryoSerializer implements Serializer {
 
    // 由於kryo不是線程安全的,所以每個線程都使用獨立的kryo
    final ThreadLocal<Kryo> kryoLocal = new ThreadLocal<Kryo>() {
        @Override
        protected Kryo initialValue() {
            Kryo kryo = new Kryo();
            kryo.register(ct, new BeanSerializer<>(kryo, ct));
            return kryo;
        }
    };
    final ThreadLocal<Output> outputLocal = new ThreadLocal<Output>();
    final ThreadLocal<Input> inputLocal = new ThreadLocal<Input>();
    private Class<?> ct = null;
 
    public kryoSerializer(Class<?> ct) {
        this.ct = ct;
    }
 
    public Class<?> getCt() {
        return ct;
    }
 
    public void setCt(Class<?> ct) {
        this.ct = ct;
    }
 
    @Override
    public void serialize(Object obj, byte[] bytes) {
        Kryo kryo = getKryo();
        Output output = getOutput(bytes);
        kryo.writeObjectOrNull(output, obj, obj.getClass());
        output.flush();
    }
 
    @Override
    public void serialize(Object obj, byte[] bytes, int offset, int count) {
        Kryo kryo = getKryo();
        Output output = getOutput(bytes, offset, count);
        kryo.writeObjectOrNull(output, obj, obj.getClass());
        output.flush();
    }
 
    /**
     * 獲取kryo
     * 
     * @param t
     * @return
     */
    private Kryo getKryo() {
        return kryoLocal.get();
    }
 
    /**
     * 獲取Output並設置初始數組
     * 
     * @param bytes
     * @return
     */
    private Output getOutput(byte[] bytes) {
        Output output = null;
        if ((output = outputLocal.get()) == null) {
            output = new Output();
            outputLocal.set(output);
        }
        if (bytes != null) {
            output.setBuffer(bytes);
        }
        return output;
    }
 
    /**
     * 獲取Output
     * 
     * @param bytes
     * @return
     */
    private Output getOutput(byte[] bytes, int offset, int count) {
        Output output = null;
        if ((output = outputLocal.get()) == null) {
            output = new Output();
            outputLocal.set(output);
        }
        if (bytes != null) {
            output.writeBytes(bytes, offset, count);
        }
        return output;
    }
 
    /**
     * 獲取Input
     * 
     * @param bytes
     * @param offset
     * @param count
     * @return
     */
    private Input getInput(byte[] bytes, int offset, int count) {
        Input input = null;
        if ((input = inputLocal.get()) == null) {
            input = new Input();
            inputLocal.set(input);
        }
        if (bytes != null) {
            input.setBuffer(bytes, offset, count);
        }
        return input;
    }
 
    @SuppressWarnings("unchecked")
    @Override
    public <T> T deserialize(byte[] bytes, int offset, int count) {
        Kryo kryo = getKryo();
        Input input = getInput(bytes, offset, count);
        return (T) kryo.readObjectOrNull(input, ct);
    }
 
    @Override
    public <T> T deserialize(byte[] bytes) {
        return deserialize(bytes, 0, bytes.length);
    }
測試一下kryo的序列化和反序列化
爲什麼使用納秒,而不用毫秒?與java原生的序列化反序列化要耗時幾毫秒不同,kryo序列化和反序列化太快了,單個對象的序列化反序列化速度都在0.0x毫秒左右(如果電腦性能更好的話,會更快)

Serializer ser = new kryoSerializer(Msg.class);
        for (int i = 0; i < 10; i++) {
 
            Msg msg = new Msg();
 
            msg.setVersion_flag(new byte[] { 1, 2, 3 });
            msg.setCrc_code((short) 1);
            msg.setMsg_body(new byte[] { 123, 123, 123, 43, 42, 1, 12, 45, 57, 98 });
            byte[] bytes = new byte[300];
            long start = System.nanoTime();
            ser.serialize(msg, bytes);
            System.err.println("序列化耗時:" + (System.nanoTime() - start));
            System.out.println(msg);
            System.out.println(Arrays.toString(bytes));
 
            Msg newmsg = null;
            start = System.nanoTime();
            newmsg = ser.deserialize(bytes);
            System.err.println("反序列化耗時:" + (System.nanoTime() - start));
            System.out.println(newmsg);
        }
----end----
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章