一、pom.xml
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>4.0.0</version>
</dependency>
二、封装工具类
package com.cxs.web.system.kryo;
import com.cxs.common.util.ArrayUtil;
import com.cxs.common.util.Collections;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.pool.KryoCallback;
import com.esotericsoftware.kryo.pool.KryoFactory;
import com.esotericsoftware.kryo.pool.KryoPool;
import org.objenesis.strategy.StdInstantiatorStrategy;
import org.springframework.util.StopWatch;
import java.io.*;
import java.util.*;
/**
* KryoUtils序列化和反序列化操作
官方文档:
中文:https://blog.csdn.net/fanjunjaden/article/details/72823866
英文:https://github.com/EsotericSoftware/kryo
*/
public class KryoUtils {
/* Kryo有三组读写对象的方法
* 1.如果不知道对象的具体类,且对象可以为null: kryo.writeClassAndObject(output, object); Object object = kryo.readClassAndObject(input);
* 2.如果类已知且对象可以为null: kryo.writeObjectOrNull(output, someObject); SomeClass someObject = kryo.readObjectOrNull(input, SomeClass.class);
* 3.如果类已知且对象不能为null: kryo.writeObject(output, someObject); SomeClass someObject = kryo.readObject(input, SomeClass.class);
*/
/**
* (池化Kryo实例)使用ThreadLocal
*/
private static final ThreadLocal<Kryo> KRYOS = new ThreadLocal<Kryo>() {
@Override
protected Kryo initialValue() {
Kryo kryo = new Kryo();
/**
* 不要轻易改变这里的配置,更改之后,序列化的格式就会发生变化,
* 上线的同时就必须清除 Redis 里的所有缓存,
* 否则那些缓存再回来反序列化的时候,就会报错
*/
//支持对象循环引用(否则会栈溢出)
kryo.setReferences(true); //默认值就是 true,添加此行的目的是为了提醒维护者,不要改变这个配置
//不强制要求注册类(注册行为无法保证多个 JVM 内同一个类的注册编号相同;而且业务系统中大量的 Class 也难以一一注册)
kryo.setRegistrationRequired(false); //默认值就是 false,添加此行的目的是为了提醒维护者,不要改变这个配置
//Fix the NPE bug when deserializing Collections.
((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy()).setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());
return kryo;
}
};
/**
* (池化Kryo实例)使用KryoPool
*/
/*private static KryoFactory factory1 = new KryoFactory() {
@Override
public Kryo create () {
return new Kryo();
}
};
private static KryoFactory factory2 = () -> { return new Kryo(); };
private static KryoFactory factory3 = () -> new Kryo();*/
private static KryoFactory factory = Kryo::new;
private static KryoPool pool = new KryoPool.Builder(factory).softReferences().build();
/**
* 使用ThreadLocal创建Kryo
* 把java对象序列化成byte[];
* @param obj java对象
* @return
*/
public static <T> byte[] serializeObject(T obj) {
ByteArrayOutputStream os=null;
Output output=null;
if(null != obj){
Kryo kryo = KRYOS.get();
try {
os = new ByteArrayOutputStream();
output = new Output(os);
kryo.writeObject(output, obj);
close(output);
return os.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}finally {
close(os);
}
}
return null;
}
/**
* 使用ThreadLocal创建Kryo
* 把byte[]反序列化成指定的java对象
* @param bytes
* @param t 指定的java对象
* @param <T>
* @return 指定的java对象
*/
public static <T> T unSerializeObject(byte[] bytes,Class<T> t) {
ByteArrayInputStream is=null;
Input input=null;
if(null != bytes && bytes.length>0 && null!=t){
try {
Kryo kryo = KRYOS.get();
is = new ByteArrayInputStream(bytes);
input = new Input(is);
return kryo.readObject(input,t);
} catch (Exception e) {
e.printStackTrace();
}finally {
close(is);
close(input);
}
}
return null;
}
/**
* 使用ThreadLocal创建Kryo
* 把List序列化成byte[];
* @param list java对象
* @return
*/
public static <T> byte[] serializeList(List<T> list ) {
ByteArrayOutputStream os=null;
Output output=null;
byte[] bytes = null;
if(null != list && list.size()>0){
Kryo kryo = KRYOS.get();
try {
os = new ByteArrayOutputStream();
output = new Output(os);
kryo.writeObject(output,list);
close(output);
bytes = os.toByteArray();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}finally {
close(os);
}
}
return null;
}
/**
* 使用ThreadLocal创建Kryo
* 把byte[]反序列化成指定的List<T>
* @param bytes byte数组
* @param <T>
* @return 指定java对象的List
*/
public static <T> List<T> unSerializeList(byte[] bytes) {
ByteArrayInputStream is=null;
Input input=null;
if(null !=bytes && bytes.length>0){
try {
Kryo kryo = KRYOS.get();
is = new ByteArrayInputStream(bytes);
input = new Input(is);
List<T> list = kryo.readObject(input,ArrayList.class);
return list;
} catch (Exception e) {
e.printStackTrace();
}finally {
close(is);
close(input);
}
}
return null;
}
/**
* 使用ThreadLocal创建Kryo
* 把java对象转序列化存储在文件中;
* @param obj java对象
* @return
*/
public static <T> boolean serializeFile(T obj,String path) {
if(null != obj){
Output output=null;
try {
Kryo kryo = KRYOS.get();
output = new Output(new FileOutputStream(path));
kryo.writeObject(output, obj);
return true;
} catch (Exception e) {
e.printStackTrace();
}finally {
close(output);
}
}
return false;
}
/**
* 使用ThreadLocal创建Kryo
* 把序列化的文件反序列化成指定的java对象
* @param path 文件路径
* @param t 指定的java对象
* @param <T>
* @return 指定的java对象
*/
public static <T> T unSerializeFile(String path,Class<T> t) {
if(null != path && null !=t ){
Input input=null;
try {
Kryo kryo = KRYOS.get();
input = new Input(new FileInputStream(path));
return kryo.readObject(input,t);
} catch (Exception e) {
e.printStackTrace();
}finally {
close(input);
}
}
return null;
}
/**
* 使用KryoPool SoftReferences创建Kryo
* 把java对象序列化成byte[] ;
* @param obj java对象
* @return
*/
public static <T> byte[] serializePoolSoftReferences (T obj) {
if(null!=obj){
Kryo kryo =pool.borrow();
ByteArrayOutputStream os=null;
Output output=null;
try {
os = new ByteArrayOutputStream();
output = new Output(os);
kryo.writeObject(output, obj);
close(output);
byte [] bytes = os.toByteArray();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}finally {
pool.release(kryo);
close(os);
}
}
return null;
}
/**
* 使用KryoPool SoftReferences创建Kryo
* 把byte[]反序列化成指定的java对象
* @param bytes
* @return
*/
public static <T> T unSerializePoolSoftReferences(byte[] bytes,Class<T> t) {
if(null !=bytes && bytes.length>0 && null!=t){
Kryo kryo =pool.borrow();
ByteArrayInputStream is=null;
Output output=null;
try {
is = new ByteArrayInputStream(bytes);
Input input= new Input(is);
return kryo.readObject(input, t);
} catch (Exception e) {
e.printStackTrace();
}finally {
pool.release(kryo);
close(is);
close(output);
}
}
return null;
}
/**
* 使用KryoPool SoftReferences创建Kryo
* 把java对象序列化成byte[] ;
* @param obj java对象
* @return
*/
public static <T> byte[] serializePoolCallback (final T obj) {
if(null != obj){
try {
return pool.run(new KryoCallback<byte[]>() {
@Override
public byte[] execute(Kryo kryo) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
Output output = new Output(os);
kryo.writeObject(output,obj);
output.close();
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
return os.toByteArray();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* 使用KryoPool SoftReferences创建Kryo
* 把byte[]反序列化成指定的java对象
* @param bytes
* @return
*/
public static <T> T unSerializePoolCallback(final byte[] bytes, final Class<T> t) {
if(null != bytes && bytes.length>0 && null != t){
try {
return pool.run(new KryoCallback<T>() {
@Override
public T execute(Kryo kryo) {
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
Input input = new Input(is);
T result =kryo.readObject(input,t);
input.close();
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* 关闭io流对象
*
* @param closeable
*/
public static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws FileNotFoundException {
Clazz clazz1 = new Clazz("3年级1班", "java", 1);
Clazz clazz2 = new Clazz("3年级2班", ".net", 2);
Clazz clazz3 = new Clazz("3年级3班", "vue", 3);
Student student1 = new Student("张三", 18, new Date(), '1', true, clazz1);
Student student2 = new Student("李四", 28, new Date(System.currentTimeMillis()-1000*60*60*24), '1', true, clazz1);
Student student3 = new Student("王五", 38, new Date(System.currentTimeMillis()-1000*60*60*24*2), '2', false, clazz2);
Student student4 = new Student("赵六", 48, new Date(System.currentTimeMillis()-1000*60*60*24*3), '1', true, clazz3);
Student student5 = new Student("刘七", 58, new Date(System.currentTimeMillis()-1000*60*60*24*4), '2', false, clazz1);
List<Student> studentList = Arrays.asList(student1, student2, student3, student4, student5);
System.out.println("===kryo序列化===");
StopWatch stopWatch = new StopWatch("kryo序列化/反序列化");
stopWatch.start("kryo序列化/反序列化");
for(int i = 0; i < 1000000; i++) {
unSerializeObject(serializeObject(studentList), ArrayList.class);
}
stopWatch.stop();
System.out.println(stopWatch.getId() + "-totalTimeMillis:" + stopWatch.getTotalTimeMillis());
System.out.println("===jdk序列化===");
stopWatch = new StopWatch("jdk序列化/反序列化");
stopWatch.start("jdk序列化/反序列化");
for(int i = 0; i < 1000000; i++) {
Collections.deepCopy(studentList);
}
stopWatch.stop();
System.out.println(stopWatch.getId() + "-totalTimeMillis:" + stopWatch.getTotalTimeMillis());
}
}
三、与jdk序列化/反序列化的性能测试
1. 循环1万次测试
测试结果:kryo高于jdk 3倍效率
2. 循环10万次测试
测试结果:kryo高于jdk 4倍效率
3. 循环100万次测试
测试结果:kryo高于jdk 5倍效率
四、总结
序列化/反序列化 次数越多,效果越明显!