Spring Boot Redis序列化全解析(7种策略)
01前言
作为一个天天跟高并发、大流量打交道的后端,选错 Redis 序列化方案,能把 4 核 8G 的云主机直接干成“拖拉机”。
1、JdkSerializationRedisSerializer
—— JVM 自带的“老爷车”
关键词:简单、兼容、性能拉胯
代码示例(含注解)
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> jdkTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);// **Key 用 String,可读性高**template.setKeySerializer(new StringRedisSerializer());// **Value 用 JDK 默认序列化**template.setValueSerializer(new JdkSerializationRedisSerializer());template.afterPropertiesSet();return template;}
}
注解:
- 只改一行 setValueSerializer,就能把任意 Serializable 对象塞进 Redis。
- 默认编码是 ISO-8859-1,中文会乱码,生产别忘 -Dfile.encoding=UTF-8。
- 每次升级类结构都要 serialVersionUID 对齐,否则线上反序列化直接爆炸。
2、StringRedisSerializer
—— 纯文本玩家的最爱
关键词:超轻量、肉眼可读、只认字符串
代码示例
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {// **StringRedisTemplate 已经帮你配好 String 序列化器**return new StringRedisTemplate(factory);
}
注解:
- 适合缓存 验证码、配置、JSON 字符串。
- 不支持直接存对象,需要手动 JSON.toJSONString。
- 命令行 redis-cli 直接能看懂,调试神器。
3、Jackson2JsonRedisSerializer
—— JSON 界的“瑞士军刀”
关键词:类型固定、易读、跨语言
代码示例
@Bean
public RedisTemplate<String, User> jacksonUserTemplate(RedisConnectionFactory factory) {RedisTemplate<String, User> template = new RedisTemplate<>();template.setConnectionFactory(factory);template.setKeySerializer(new StringRedisSerializer());// **指定 User.class,防止反序列化翻车**Jackson2JsonRedisSerializer<User> ser = new Jackson2JsonRedisSerializer<>(User.class);ObjectMapper om = new ObjectMapper();om.activateDefaultTyping(...); // 省略配置,启用多态ser.setObjectMapper(om);template.setValueSerializer(ser);return template;
}
注解:
- 必须提前声明类型,泛型、多态场景会哭。
- 序列化后体积比 JDK 小 60%,性能高 3 倍。
- 前端、Python、Go 直接读缓存无压力,跨语言首选。
4、GenericJackson2JsonRedisSerializer
—— 不挑类型的“全能选手”
关键词:无类型也能玩、自动带类信息、体积稍大
代码示例
@Bean
public RedisTemplate<String, Object> genericJacksonTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);GenericJackson2JsonRedisSerializer generic = new GenericJackson2JsonRedisSerializer();template.setDefaultSerializer(generic); // **一把梭,啥都能塞**return template;
}
注解:
- JSON 里自带 @class,反序列化不迷路。
- 体积比上一种再膨胀 15%,纯 Java 后台可忽略。
- 重构包名/类名时别忘了做迁移脚本,否则缓存全部失效。
5、FastJsonRedisSerializer
—— 阿里出品的“性能小钢炮”
关键词:速度怪兽、配置少、注意漏洞
代码示例
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {private final Class<T> clazz;public FastJsonRedisSerializer(Class<T> clazz) { this.clazz = clazz; }@Overridepublic byte[] serialize(T t) {return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);}@Overridepublic T deserialize(byte[] bytes) {return JSON.parseObject(new String(bytes, StandardCharsets.UTF_8), clazz);}
}
注解:
- 1.2.83 以下版本有 RCE 漏洞,直接上 Fastjson2.x。
- 序列化速度比 Jackson 再快 50%,日志埋点、秒杀缓存首选。
- 非 Java 语言解析不了 @type,跨语言慎入。
6、Kryo
—— 二进制“压缩神器”
关键词:极致性能、体积小、可读性 0
代码示例
public class KryoRedisSerializer<T> implements RedisSerializer<T> {private final Class<T> clazz;private final ThreadLocal<Kryo> kryo = ThreadLocal.withInitial(() -> {Kryo k = new Kryo();k.setRegistrationRequired(false); // 允许未注册类k.setReferences(true); // 支持循环引用return k;});public KryoRedisSerializer(Class<T> clazz) { this.clazz = clazz; }@Overridepublic byte[] serialize(T obj) {ByteArrayOutputStream bos = new ByteArrayOutputStream();Output output = new Output(bos);kryo.get().writeObject(output, obj);output.close();return bos.toByteArray();}@Overridepublic T deserialize(byte[] bytes) {if (bytes == null) return null;Input input = new Input(bytes);return kryo.get().readObject(input, clazz);}
}
注解:
- 序列化速度 ≈ JSON 的 5 倍,体积 ≈ JSON 的 30%。
- 二进制不可读,出问题只能抓包。
- 需要 ThreadLocal 保证线程安全,高并发稳得很。
7、Protobuf
—— Google 的“跨语言契约”
关键词:IDL 先行、极致压缩、前后兼容
proto 文件
syntax = "proto3";
package com.demo;message User {int64 id = 1;string name = 2;repeated string roles = 3;
}
序列化器代码
public class ProtobufRedisSerializer<T extends Message> implements RedisSerializer<T> {private final Parser<T> parser;public ProtobufRedisSerializer(Parser<T> parser) { this.parser = parser; }@Overridepublic byte[] serialize(T message) {return message == null ? new byte[0] : message.toByteArray();}@Overridepublic T deserialize(byte[] bytes) {if (bytes == null || bytes.length == 0) return null;try {return parser.parseFrom(bytes);} catch (InvalidProtocolBufferException e) {throw new SerializationException("Protobuf decode error", e);}}
}
注解:
- 通过 .proto 生成代码,类型安全到字段级别。
- 新增字段只要 reserved 老标签,版本升级无感。
- 不支持动态结构,活动配置、实时 schema 场景绕行。
如何选型?
- Key 一律 StringRedisSerializer,排查不烧脑。
-
- Value 按场景选:内部 Kryo,对外 JSON,跨语言 Protobuf。
-
- 升级类结构前,先灰度双写,缓存雪崩比 bug 更疼。