SpringBoot2.x—自定义Protostuff方式的RedisSerializer

SpringBoot2.X整合Redis缓存
SpringBoot2.x集成SpringCache+Redis

1. 如何实现自定义ProtostuffRedisSerializer

在SpringBoot2.x环境下,若想使用Redis作为缓存,我们势必要选择一种合适的序列化工具。Redis提供了一个公共接口org.springframework.data.redis.serializer.RedisSerializer<T>。来完成数据的序列化和反序列化。

public interface RedisSerializer<T> {

    @Nullable
    byte[] serialize(@Nullable T t) throws SerializationException;

    @Nullable
    T deserialize(@Nullable byte[] bytes) throws SerializationException;

    static RedisSerializer<Object> java() {
        return java(null);
    }

    static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {
        return new JdkSerializationRedisSerializer(classLoader);
    }

    static RedisSerializer<Object> json() {
        return new GenericJackson2JsonRedisSerializer();
    }

    static RedisSerializer<String> string() {
        return StringRedisSerializer.UTF_8;
    }
}

我们若想使用Protostuff作为Redis序列化数据的工具,那么就必须实现该接口。

引入依赖

       <dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-runtime</artifactId>
            <version>1.6.0</version>
        </dependency>

        <dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-core</artifactId>
            <version>1.6.0</version>
        </dependency>

实现接口

public class ProtoStuffRedisSerializer implements RedisSerializer<Object> {

    private static final Schema<ObjectWrapper> schema = RuntimeSchema.getSchema(ObjectWrapper.class);

    @Override
    public byte[] serialize(Object t) throws SerializationException {
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        byte[] bytes;
        try {
            bytes = ProtostuffIOUtil.toByteArray(new ObjectWrapper(t), schema, buffer);
        } finally {
            buffer.clear();
        }
        return bytes;
    }

    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        try {
            ObjectWrapper objectWrapper = new ObjectWrapper();
            ProtostuffIOUtil.mergeFrom(bytes, objectWrapper, schema);
            return objectWrapper.getObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static class ObjectWrapper {
        private Object object;

        ObjectWrapper() {
        }

        ObjectWrapper(Object object) {
            this.object = object;
        }

        public Object getObject() {
            return object;
        }

        public void setObject(Object object) {
            this.object = object;
        }
    }
}

2. 性能比较

在Redis的包中,默认提供了几种序列化的工具,如JDK、Jackson、Fastjson等等,我们自定义实现序列化方式性能和官方默认的差距如何呢?

   public void getAccInfoByTime(String customerId, String accType) {
        //获取Bean对象
        Account accInfo = getAccInfo(customerId, accType);
        //JDK的序列化时间
        JdkSerializationRedisSerializer jdk = new JdkSerializationRedisSerializer();
        ProtoStuffRedisSerializer pro = new ProtoStuffRedisSerializer();
        Jackson2JsonRedisSerializer jackson = new Jackson2JsonRedisSerializer(Object.class);
        byte[] jdkBytes = getSerializeTime("JDK序列化", () -> jdk.serialize(accInfo));
        byte[] proBytes = getSerializeTime("PRO序列化", () -> pro.serialize(accInfo));
        byte[] jacksonBytes = getSerializeTime("JACK序列化", () -> jackson.serialize(accInfo));
        Object deserializeTime = getDeserializeTime("JDK反序列化时间:", () -> jdk.deserialize(jdkBytes));
        Object deserializeTime1 = getDeserializeTime("PRO反序列化时间:", () -> pro.deserialize(proBytes));
        Object deserializeTime2 = getDeserializeTime("JACK序列化时间:", () -> jackson.deserialize(jacksonBytes));
    }

    /**
     * 计算序列化的耗时时间
     *
     * @param supplier
     * @return
     */
    private byte[] getSerializeTime(String desc, Supplier<byte[]> supplier) {
        long startTime = System.currentTimeMillis();
        byte[] bytes = supplier.get();
        System.out.println(desc + "时间:" + (System.currentTimeMillis() - startTime) + " ms");
        System.out.println(desc + "大小:" + bytes.length + " b");
        return bytes;
    }


    /**
     * 计算反的耗时时间
     *
     * @param supplier
     * @return
     */
    private Object getDeserializeTime(String desc, Supplier<Object> supplier) {
        long startTime = System.currentTimeMillis();
        Object obj = supplier.get();
        System.out.println(desc + (System.currentTimeMillis() - startTime) + " ms");
        return obj;
    }

执行结果:

JDK序列化时间:0 ms
JDK序列化大小:865 b
PRO序列化时间:0 ms
PRO序列化大小:155 b
JACK序列化时间:15 ms
JACK序列化大小:447 b

JDK反序列化时间:1 ms
PRO反序列化时间:0 ms
JACK反序列化时间:2 ms

可以看到,protostuff在压缩时间,以及压缩后的大小上都是比较占优的。

文章推荐

CacheManager以及序列化类

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。