整合 Kryo 到 spring 您所在的位置:网站首页 redistemplate序列化器比较 整合 Kryo 到 spring

整合 Kryo 到 spring

2023-11-29 03:05| 来源: 网络整理| 查看: 265

整合 Kryo 到 spring-boot-starter-data-redis 中

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 1 天,点击查看活动详情。

前言

最近在公司有接触到 Redis 性能优化的工作,项目中代码大量使用 JSON 字符串作为 Value 的存储方式,这样的方式并不是最优的。从空间资源占用角度来看,在将 JavaBean 序列化到 Redis 中存储时,可以将其序列化为字节数组再存储。这样的好处是序列化后的数据占用空间更小,代价便于增加了序列化与反序列化的时间开销。

spring-boot-starter-data-redis 自带的几个序列化框架中,其中就有针对字节数组的优化方式,JdkSerializationRedisSerializer 但它的性能并不是最优的,推荐使用 Kryo 框架——时间和空间都是目前已知的序列化框架中最优的。

Kryo 整合 1. 引入 Maven 依赖        com.esotericsoftware      kryo      5.3.0   2. Kryo 的基本使用  Kryo kryo = new Kryo();  // 允许循环引用存在  kryo.setReferences(true);  // 允许不注册对象的类型  kryo.setRegistrationRequired(false);  ​  // 根据对象的类型序列化对象,并写入  kryo.writeObject(output, obj);  // 允许写入对象为空  kryo.writeObjectOrNull(output, obj, User.class);  // 将对象的类信息也写入到字节数组中  kryo.writeClassAndObject(output, obj);  ​  // 根据类对象反序列字节数组  T t = kryo.readObject(input, clazz);  // 根据类对象反序列字节数组(字节数据可能为空)  T objectOrNull = kryo.readObjectOrNull(input, clazz);  // 反序列字节数组,反序列化之后的对象信息在字节数组中  Object object = kryo.readClassAndObject(input);

在 RPC 调用中,往往不方便确定原始对象类型,因此一般建议将对象类消息也序列化到字节数组中,然后反序列化时的类信息也从字节数组中读取。

3. 整合到 Redis 中

想要整合到 Redis 中无缝使用,只需要自定义 RedisTemplate 的 Key 或 Value 的序列化框架为 Kyro 即可。

以 StringRedisTemplate 为例,主要有 3 个关键步骤

 // 1. 实现 RedisSerializer 接口  public class StringRedisSerializer implements RedisSerializer {  ​    // 2. 反序列化方法(byte[] -> String)   @Override   public String deserialize(@Nullable byte[] bytes) {   return (bytes == null ? null : new String(bytes, charset));   }  ​   // 3. 序列化方法 (String -> byte[])   @Override   public byte[] serialize(@Nullable String string) {   return (string == null ? null : string.getBytes(charset));   }  ​  }  ​

新建自定义序列化工具类 KryoRedisSerializer

 @Component  @NoArgsConstructor  public class KryoRedisSerializer implements RedisSerializer {  ​      /**       * 由于 Kryo 不是线程安全的。每个线程都应该有自己的 Kryo,Input 或 Output 实例。       * 所以,使用 ThreadLocal 存放 Kryo 对象       * 这样减少了每次使用都实例化一次 Kryo 的开销又可以保证其线程安全       */      private static final ThreadLocal KRYO_THREAD_LOCAL = ThreadLocal.withInitial(() -> {          Kryo kryo = new Kryo();       // 设置循环引用          kryo.setReferences(true);       // 设置序列化时对象是否需要设置对象类型          kryo.setRegistrationRequired(false);          return kryo;     });  ​      public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];  ​      @Override      public byte[] serialize(Object t) throws SerializationException {          if (t == null) {              return EMPTY_BYTE_ARRAY;         }          try (ByteArrayOutputStream baos = new ByteArrayOutputStream();               Output output = new Output(baos)) {              Kryo kryo = KRYO_THREAD_LOCAL.get();              // 对象的 Class 信息一起序列化              kryo.writeClassAndObject(output, t);              KRYO_THREAD_LOCAL.remove();              return output.toBytes();         } catch (Exception e) {              throw new SerializationException("Could not write byte[]: " + e.getMessage(), e);         }     }  ​      @Override      public T deserialize(byte[] bytes) throws SerializationException {          if (bytes == null || bytes.length


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有