前言:kryo是個高效的java序列化/反序列化庫,目前Twitter、yahoo、Apache、strom等等在使用該技術,好比Apache的spark、hive等大數據領域用的較多。java
由於性能足夠好。比kyro更高效的序列化庫就只有google的protobuf了(並且二者性能很接近),protobuf有個缺點就是要傳輸的每個類的結構都要生成對應的proto文件(也能夠都放在同一個proto文件中,若是考慮到擴展性的話,不建議放在一個proto文件中),若是某個類發生修改,還得從新生成該類對應的proto文件;另外考慮到項目中用的所有是java技術棧,不存在不一樣編程語言間的兼容性問題,所以最終採用了kryo做爲序列化庫。
redis
使用場景:(數據交換或數據持久化)好比使用kryo把對象序列化成字節數組發送給消息隊列或者放到redis等nosql中等等應用場景。sql
注意:因爲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); }
/** * 基於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); }
爲何使用納秒,而不用毫秒?與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----