概述
使用Spring 提供的 Spring Data Redis 操作redis 必然要使用Spring提供的模板类 RedisTemplate, 今天我们好好的看看这个模板类 。
RedisTemplate
Redis - RedisTemplate及4种序列化方式深入解读 - 图1
看看4个序列化相关的属性 ,主要是 用于 KEY 和 VALUE 的序列化 。 举个例子,比如说我们经常会将POJO 对象存储到 Redis 中,一般情况下会使用 JSON 方式序列化成字符串,存储到 Redis 中 。
Spring提供的Redis数据结构的操作类

  1. ValueOperations 类,提供 Redis String API 操作
  2. ListOperations 类,提供 Redis List API 操作
  3. SetOperations 类,提供 Redis Set API 操作
  4. ZSetOperations 类,提供 Redis ZSet(Sorted Set) API 操作
  5. GeoOperations 类,提供 Redis Geo API 操作
  6. HyperLogLogOperations 类,提供 Redis HyperLogLog API 操作

StringRedisTemplate

再看个常用的 StringRedisTemplate,RedisTemplate 支持泛型,StringRedisTemplate K V 均为String类型。
org.springframework.data.redis.core.StringRedisTemplate 继承 RedisTemplate 类,使用 org.springframework.data.redis.serializer.StringRedisSerializer 字符串序列化方式。
Redis - RedisTemplate及4种序列化方式深入解读 - 图2
RedisSerializer 序列化 接口
RedisSerializer接口 是 Redis 序列化接口,用于 Redis KEY 和 VALUE 的序列化
Redis - RedisTemplate及4种序列化方式深入解读 - 图3
RedisSerializer 接口的实现类 如下
Redis - RedisTemplate及4种序列化方式深入解读 - 图4
归类一下

  • JDK 序列化方式 (默认)
  • String 序列化方式
  • JSON 序列化方式
  • XML 序列化方式

    JDK 序列化方式 (默认)

    org.springframework.data.redis.serializer.JdkSerializationRedisSerializer ,默认情况下,RedisTemplate 使用该数据列化方式。我们来看下源码 RedisTemplate#afterPropertiesSet()
    Redis - RedisTemplate及4种序列化方式深入解读 - 图5
    Spring Boot 自动化配置 RedisTemplate Bean 对象时,就未设置默认的序列化方式。
    绝大多数情况下,不推荐使用 JdkSerializationRedisSerializer 进行序列化。主要是不方便人工排查数据。
    我们来做个测试
    Redis - RedisTemplate及4种序列化方式深入解读 - 图6
    运行单元测试
    Redis - RedisTemplate及4种序列化方式深入解读 - 图7
    看不懂呀 ,老哥
    KEY 前面带着奇怪的 16 进制字符 , VALUE 也是一串奇怪的 16 进制字符 。。。。。

    为什么是这样一串奇怪的 16 进制? ObjectOutputStream#writeString(String str, boolean unshared) 实际就是标志位 + 字符串长度 + 字符串内容

KEY 被序列化成这样,线上通过 KEY 去查询对应的 VALUE非常不方便,所以 KEY 肯定是不能被这样序列化的。
VALUE 被序列化成这样,除了阅读可能困难一点,不支持跨语言外,实际上也没还OK。不过,实际线上场景,还是使用 JSON 序列化居多。

String 序列化方式

org.springframework.data.redis.serializer.StringRedisSerializer ,字符串和二进制数组的直接转换
Redis - RedisTemplate及4种序列化方式深入解读 - 图8
绝大多数情况下,我们 KEY 和 VALUE 都会使用这种序列化方案。

JSON 序列化方式

org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer 使用 Jackson 实现 JSON 的序列化方式,并且从 Generic 单词可以看出,是支持所有类。

  1. public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName) {
  2. if (StringUtils.hasText(classPropertyTypeName)) {
  3. mapper.enableDefaultTypingAsProperty(DefaultTyping.NON_FINAL, classPropertyTypeName);
  4. } else {
  5. mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
  6. }
  7. }

classPropertyTypeName 不为空的话,使用传入对象的 classPropertyTypeName 属性对应的值,作为默认类型(Default Typing) ,否则使用传入对象的类全名,作为默认类型(Default Typing)。

我们来思考下,在将一个对象序列化成一个字符串,怎么保证字符串反序列化成对象的类型呢?Jackson 通过 Default Typing ,会在字符串多冗余一个类型,这样反序列化就知道具体的类型了
先说个结论
标准JSON

  1. {
  2. "id": 100,
  3. "name": "小工匠",
  4. "sex": "Male"
  5. }

使用 Jackson Default Typing 机制序列化

  1. {
  2. "@class": "com.artisan.domain.Artisan",
  3. "id": 100,
  4. "name": "小工匠",
  5. "sex": "Male"
  6. }

示例
测试一把

  1. @Bean
  2. public RedisTemplate<String, Object> redisTemplate() {
  3. // 创建 RedisTemplate 对象
  4. RedisTemplate<String, Object> template = new RedisTemplate<>();
  5. // 设置 RedisConnection 工厂。 它就是实现多种 Java Redis 客户端接入的秘密工厂
  6. template.setConnectionFactory(connectionFactory);
  7. // 使用 String 序列化方式,序列化 KEY 。
  8. template.setKeySerializer(RedisSerializer.string());
  9. // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。
  10. template.setValueSerializer(RedisSerializer.json());
  11. return template;
  12. }

【配置类】

  1. @Test
  2. public void testJacksonSerializer() {
  3. Artisan artisan = new Artisan();
  4. artisan.setName("小工匠");
  5. artisan.setId(100);
  6. artisan.setSex("Male");
  7. // set
  8. redisTemplate.opsForValue().set("artisan", artisan);
  9. }

【结果】
Redis - RedisTemplate及4种序列化方式深入解读 - 图9

使用FastJson配置:https://blog.csdn.net/chen15369337607/article/details/104058934

使用FastJson

  1. @Bean
  2. public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory, RedisSerializer fastJson2JsonRedisSerializer) {
  3. RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
  4. redisTemplate.setConnectionFactory(factory);
  5. //key采用String序列化方式
  6. StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
  7. redisTemplate.setKeySerializer(stringRedisSerializer);
  8. redisTemplate.setHashKeySerializer(stringRedisSerializer);
  9. //value采用fast-json序列化方式。
  10. redisTemplate.setValueSerializer(fastJson2JsonRedisSerializer);
  11. redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerializer);
  12. redisTemplate.afterPropertiesSet();
  13. return redisTemplate;
  14. }
  15. @Bean
  16. public RedisSerializer fastJson2JsonRedisSerializer() {
  17. return new FastJson2JsonRedisSerializer<>(Object.class);
  18. }
  19. public static class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
  20. public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
  21. private Class<T> clazz;
  22. public FastJson2JsonRedisSerializer(Class<T> clazz) {
  23. super();
  24. this.clazz = clazz;
  25. }
  26. @Override
  27. public byte[] serialize(T t) throws SerializationException {
  28. if (t == null) {
  29. return new byte[0];
  30. }
  31. return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
  32. }
  33. @Override
  34. public T deserialize(byte[] bytes) throws SerializationException {
  35. if (bytes == null || bytes.length <= 0) {
  36. return null;
  37. }
  38. String str = new String(bytes, DEFAULT_CHARSET);
  39. return JSON.parseObject(str, clazz, Feature.SupportAutoType);
  40. }
  41. }


RedisTemplate配置序列化器无效

https://www.programminghunter.com/article/44392106736/