前言: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----