RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,
使用默认配置的 RedisTemplate 会遇到序列化问题,根本原因在于它默认使用 JDK 序列化。这会导致两个直接的麻烦:
- 可读性极差:存入 Redis 的数据会变成不可读的二进制乱码,无法通过 redis-cli 等工具直观地查看和调试。
- 存储空间浪费:JDK 序列化会存储完整的类元信息,占用更多内存。
因此,为了获得更好的可读性和存储效率,自定义 RedisTemplate 的序列化方式就非常必要了。
自定义 RedisTemplate 配置
在项目里添加一个配置类,通常就是把 key 设为 String 序列化,value 设为 JSON 序列化。
下面是一份可以直接参考的配置模板:
java
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用 Jackson2JsonRedisSerializer 来序列化和反序列化 redis 的 value 值
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 启用默认类型信息,这样反序列化时能知道具体的类,否则会变成 LinkedHashMap
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// key 采用 String 的序列化方式
template.setKeySerializer(new StringRedisSerializer());
// value 采用 Jackson 的序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash 的 key 也采用 String 的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
// hash 的 value 采用 Jackson 的序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
这份配置解决了前面提到的可读性问题,同时也处理了 LocalDateTime 等复杂对象的序列化,是业界比较通用的方案。
关于 Jackson 序列化器的选择
在选择具体的 JSON 序列化器时,常看到两个选项,它们的区别是这样的:
| 特性 | Jackson2JsonRedisSerializer | GenericJackson2JsonRedisSerializer |
|---|---|---|
| 类型信息 | 不存储类型信息,序列化结果更简洁 | 自动存储类型信息(如 @class 字段) |
| 反序列化 | 需要显式指定目标类型 | 可自动识别类型,使用更便捷 |
| 存储开销 | 较小 | 较大(需额外存储类型信息) |
简单来说:
- 如果追求存储空间效率 ,且能明确知道要反序列化的目标类型,选
Jackson2JsonRedisSerializer。 - 如果追求使用便捷性 ,希望反序列化能自动完成,选
GenericJackson2JsonRedisSerializer。
大多数场景下,为了方便,直接用 GenericJackson2JsonRedisSerializer 就好。但需要注意,它会把数字类型(如 Long)反序列化成 Integer,取值时可能报类型转换错误,这一点需要留意。
另一种思路:StringRedisTemplate
除了自定义 RedisTemplate,还有一种更轻量的做法:使用 Spring 已经提供的 StringRedisTemplate。它的 key 和 value 都强制使用 String 序列化,你只需要在代码里手动把对象转成 JSON 字符串再存进去就行。
- 优点:完全省去自定义配置,手动序列化让存储格式完全可控,非常节省空间。
- 缺点:代码里需要多写一步序列化和反序列化,稍微繁琐一点。