目录
  • 前言
  • 配置类
    • 配置 Jackson2JsonRedisSerializer 序列化策略
    • 配置  RedisTemplate
    • 配置缓存策略
  • 测试代码
    • 完整代码

      前言

      最近在学习Spring Boot结合Redis时看了一些网上的教程,发现这些教程要么比较老,要么不知道从哪抄得,运行起来有问题。这里分享一下我最新学到的写法

      默认情况下,Spring 为我们提供了一个 RedisTemplate 来进行对 Redis 的操作,但是 RedisTemplate 默认配置的是使用Java本机序列化。

      这种序列化方式,对于操作字符串或数字来说,用起来还行,但是如果要对对象操作,就不是那么的方便了。

      所以我们需要配置合适的序列化方式。在 Spring 官方的文档中,官方也建议了我们使用其他的方式来进行序列化。比如JSON

      SpringBoot结合Redis实现序列化的方法详解

      https://docs.spring.io/spring-data/redis/docs/2.2.5.RELEASE/reference/html/#redis:serializer

      配置类

      配置 Jackson2JsonRedisSerializer 序列化策略

      下面就开始自动配置类的书写

      我使用的是 Jackson2JsonRedisSerializer 来对对象进行序列化,所以首先需要一个方法,来配置 Jackson2JsonRedisSerializer 序列化策略

      private Jackson2JsonRedisSerializer<Object> serializer() {
              // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
              Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
              ObjectMapper objectMapper = new ObjectMapper();
      
              // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
              objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
      
              // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
              objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
      
              jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
              return jackson2JsonRedisSerializer;
          }

      这里要注意的是

      objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

      这一句,这一句非常的重要,作用是序列化时将对象全类名一起保存下来

      设置之后的序列化结果如下:

      [
          "com.buguagaoshu.redis.model.User",
          {
              "name": "1",
              "age": "11",
              "message": "牛逼"
          }
      ]

      不设置的话,序列化结果如下,将无法反序列化

      {
              "name": "1",
              "age": "11",
              "message": "牛逼"
          }

      一开始,我在网上搜了一下,发现大多数教程因为时间的原因,这一句用的是

      objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

      但当我把这段代码写入的时候,发现Idea提示我

      SpringBoot结合Redis实现序列化的方法详解

      着是一个过时的方法,由于我当时并不知道这句话的意思,就把这段代码注释了,觉得可能没什么用,但注释后在向Redis里写数据的时候,数据会变成

      SpringBoot结合Redis实现序列化的方法详解

      SpringBoot结合Redis实现序列化的方法详解

      导致数据无法反序列化。

      最后我查看了这个方法的源码,找到了

      SpringBoot结合Redis实现序列化的方法详解

      SpringBoot结合Redis实现序列化的方法详解

      通过注释,我得到了这段代码的最新写法。

      也明白了这段代码的作用。

      配置  RedisTemplate

      @Bean
          public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
              RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
              redisTemplate.setConnectionFactory(redisConnectionFactory);
              // 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
              redisTemplate.setValueSerializer(serializer());
      
              StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
              // 使用StringRedisSerializer来序列化和反序列化redis的key值
              redisTemplate.setKeySerializer(stringRedisSerializer);
      
              // hash的key也采用String的序列化方式
              redisTemplate.setHashKeySerializer(stringRedisSerializer);
              // hash的value序列化方式采用jackson
              redisTemplate.setHashValueSerializer(serializer());
              redisTemplate.afterPropertiesSet();
              return redisTemplate;
          }

      这里就没有什么需要注意的了,按照自己的需求,来配置序列化的方式

      配置缓存策略

      @Bean
          public CacheManager cacheManager(RedisConnectionFactory factory) {
              RedisSerializer<String> redisSerializer = new StringRedisSerializer();
              // 配置序列化(解决乱码的问题)
              RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                      // 缓存有效期
                      .entryTtl(timeToLive)
                      // 使用StringRedisSerializer来序列化和反序列化redis的key值
                      .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                      // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
                      .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer()))
                      // 禁用空值
                      .disableCachingNullValues();
      
              return RedisCacheManager.builder(factory)
                      .cacheDefaults(config)
                      .build();
          }

      测试代码

      @SpringBootTest
      public class RedisApplicationTests {
          @Autowired
          private RedisTemplate<String, Object> redisTemplate;
      
      
          @Test
          void contextLoads() throws Exception {
              User user = new User();
              user.setName("15");
              user.setAge(20);
              user.setMessage("牛逼");
              redisTemplate.opsForValue().set(user.getName(), user);
              User getUser = (User) redisTemplate.opsForValue().get(user.getName());
              System.out.println(getUser);
              System.out.println(getUser.getMessage());
          }
      
      }

      再来查看Redis中的数据

      SpringBoot结合Redis实现序列化的方法详解

      数据正常,并且系统也能正常的反序列化了。

      完整代码

      package com.buguagaoshu.redis.config;
      
      
      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.beans.factory.annotation.Value;
      import org.springframework.cache.CacheManager;
      import org.springframework.cache.annotation.CachingConfigurerSupport;
      import org.springframework.cache.annotation.EnableCaching;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.data.redis.cache.RedisCacheConfiguration;
      import org.springframework.data.redis.cache.RedisCacheManager;
      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.RedisSerializationContext;
      import org.springframework.data.redis.serializer.RedisSerializer;
      import org.springframework.data.redis.serializer.StringRedisSerializer;
      
      import java.time.Duration;
      
      /**
       * @author Pu Zhiwei {@literal puzhiweipuzhiwei@foxmail.com}
       * create          2020-03-17 21:08
       * 继承 CachingConfigurerSupport,为了自定义生成 KEY 的策略。可以不继承。
       */
      @Configuration
      @EnableCaching
      public class RedisConfig extends CachingConfigurerSupport {
          @Value("${spring.cache.redis.time-to-live}")
          private Duration timeToLive = Duration.ZERO;
      
          /**
           * 配置Jackson2JsonRedisSerializer序列化策略
           * */
          private Jackson2JsonRedisSerializer<Object> serializer() {
              // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
              Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
              ObjectMapper objectMapper = new ObjectMapper();
      
              // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
              objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
      
              objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
      
              // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
              objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
      
              jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
              return jackson2JsonRedisSerializer;
          }
      
      
          @Bean
          public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
              RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
              redisTemplate.setConnectionFactory(redisConnectionFactory);
              // 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
              redisTemplate.setValueSerializer(serializer());
      
              StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
              // 使用StringRedisSerializer来序列化和反序列化redis的key值
              redisTemplate.setKeySerializer(stringRedisSerializer);
      
              // hash的key也采用String的序列化方式
              redisTemplate.setHashKeySerializer(stringRedisSerializer);
              // hash的value序列化方式采用jackson
              redisTemplate.setHashValueSerializer(serializer());
              redisTemplate.afterPropertiesSet();
              return redisTemplate;
          }
      
      
      
      
          @Bean
          public CacheManager cacheManager(RedisConnectionFactory factory) {
              RedisSerializer<String> redisSerializer = new StringRedisSerializer();
              // 配置序列化(解决乱码的问题)
              RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                      // 缓存有效期
                      .entryTtl(timeToLive)
                      // 使用StringRedisSerializer来序列化和反序列化redis的key值
                      .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                      // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
                      .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer()))
                      // 禁用空值
                      .disableCachingNullValues();
      
              return RedisCacheManager.builder(factory)
                      .cacheDefaults(config)
                      .build();
          }
      }

      以上就是SpringBoot结合Redis实现序列化的方法详解的详细内容,更多关于SpringBoot Redis序列化的资料请关注其它相关文章!

      声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。