Kryo 高性能序列化和反序列化

一、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倍效率

四、总结

序列化/反序列化 次数越多,效果越明显!

猜你喜欢

转载自blog.csdn.net/a251628111/article/details/109309500