整合 Kryo 到 spring | 您所在的位置:网站首页 › redistemplate序列化器比较 › 整合 Kryo 到 spring |
整合 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 实验室设备网 版权所有 |