SpringBoot 配置RedisTemplate 使用 FastJson 进行序列化

前言

在我们项目进行开发时,不可避免的会使用到Redis,Spring官方给我们提供了RedisTemplate这个类,它替我们封装提供了Redis基本上全部的常用操作。而官方默认使用的序列化方式为Sdk提供的序列化类。下面讲如何替换SpringBoot默认序列化方式,并解决一些问题

依赖版本

SpringBoot版本:2.2.6

SpringBoot-redis-starter版本:2.2.6

FastJson版本:1.2.68

JDK:1.8

自定义序列化方式

  1. 我们在使用官方提供的``FastJsonRedisSerializer`时,从Redis取回的数据,为JSONObject或JSONArray类型,需要手动转换成自己需要的实体。

  2. 官方还提供了另外一个GenericFastJsonRedisSerializer序列化工具,这个类会根据我们的实体类型,从Redis取回的数据,自动反序列化为相应的实体对象。但是不知道是不是FastJson版本问题,就算GenericFastJsonRedisSerializer源码里已经设置过AutoType为True但是在实际使用过程中,反序列化一些集合类型的数据时还是会出现autoType is not support.的异常导致序列化失败

    GenericFastJsonRedisSerializer源码:

    package com.alibaba.fastjson.support.spring;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.ParserConfig;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import com.alibaba.fastjson.util.IOUtils;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.SerializationException;
    
    /**
     * {@link RedisSerializer} FastJson Generic Impl
     * @author lihengming
     * @since 1.2.36
     */
    public class GenericFastJsonRedisSerializer implements RedisSerializer<Object> {
        private final static ParserConfig defaultRedisConfig = new ParserConfig();
        static { defaultRedisConfig.setAutoTypeSupport(true);}// 这里设置AutoType为True解决序列化失败autoType is not support的问题
    
        public byte[] serialize(Object object) throws SerializationException {
            if (object == null) {
                return new byte[0];
            }
            try {
                return JSON.toJSONBytes(object, SerializerFeature.WriteClassName);
            } catch (Exception ex) {
                throw new SerializationException("Could not serialize: " + ex.getMessage(), ex);
            }
        }
    
        public Object deserialize(byte[] bytes) throws SerializationException {
            if (bytes == null || bytes.length == 0) {
                return null;
            }
            try {
                return JSON.parseObject(new String(bytes, IOUtils.UTF8), Object.class, defaultRedisConfig);
            } catch (Exception ex) {
                throw new SerializationException("Could not deserialize: " + ex.getMessage(), ex);
            }
        }
    }
    
    
  3. 自定义序列化类:FastJsonRedisSerializer

    在Debug过程中,发现在反序列化时报了异常并且反序列化失败,但是如果在其失败后再次进行反序列化就可以正常进行反序列化操作了,所以采用了一个笨方法来解决这个问题,就是在反序列化时加入一次重试操作。

    源码:

    package com.yxh.www.redis.conf;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.ParserConfig;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.SerializationException;
    
    import java.nio.charset.Charset;
    import java.util.HashMap;
    
    /**
     * <p>
     * FastJson序列化
     * </p>
     *
     * @author yangxiaohui
     * @since 2020/5/18
     */
    public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
        /**
         * 解决反序列化时Could not deserialize: autoType is not support. 的问题
         */
        private final static ParserConfig defaultRedisConfig = new ParserConfig();
    
        static {
            defaultRedisConfig.setAutoTypeSupport(true);
        }
    
        /**
         * DEFAULT_CHARSET <br>
         */
        public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
        /**
         * clazz 反序列化类<br>
         */
        private Class<T> clazz;
    
        public FastJsonRedisSerializer(Class<T> clazz) {
            super();
            this.clazz = clazz;
        }
    
        /**
         * 序列化
         *
         * @param t 对象
         * @return 字节码
         * @throws SerializationException 序列化异常
         */
        @Override
        public byte[] serialize(T t) throws SerializationException {
            if (t == null) {
                return new byte[0];
            }
            return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
        }
    
        /**
         * 反序列化
         *
         * @param bytes 字节码
         * @return 对象
         */
        @Override
        public T deserialize(byte[] bytes) throws SerializationException {
            if (bytes == null || bytes.length <= 0) {
                return null;
            }
            String str = new String(bytes, DEFAULT_CHARSET);
            try {
                return (T) JSON.parseObject(str, clazz, defaultRedisConfig);
            }catch (Exception e){
                // 如果报错,再次反序列化并返回
                return (T) JSON.parseObject(str, clazz, defaultRedisConfig);
            }
        }
    }
    
    
    1. 新建RedisConf配置类 :

      package com.yxh.www.redis.conf;
      
      import com.alibaba.fastjson.parser.ParserConfig;
      import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
      import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
      import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
      import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
      import org.springframework.boot.context.properties.EnableConfigurationProperties;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.dao.DataAccessException;
      import org.springframework.data.redis.connection.*;
      import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.data.redis.core.StringRedisTemplate;
      import org.springframework.data.redis.serializer.StringRedisSerializer;
      
      import java.net.UnknownHostException;
      
      /**
       * <p>
       *  Redis配置
       * </p>
       *
       * @author yangxiaohui
       * @since 2020/5/7
       */
      @SuppressWarnings("all")
      @Configuration
      public class RedisConf {
          @Bean
          public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
              RedisTemplate<String, Object> template = new RedisTemplate<>();
              template.setConnectionFactory(redisConnectionFactory);
              FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);
              // value值的序列化采用fastJsonRedisSerializer
              template.setValueSerializer(serializer);
              template.setHashValueSerializer(serializer);
              // key的序列化采用StringRedisSerializer
              template.setKeySerializer(new StringRedisSerializer());
              template.setHashKeySerializer(new StringRedisSerializer());
              template.setConnectionFactory(redisConnectionFactory);
              template.afterPropertiesSet();
              return template;
          }
          @Bean
          public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
              StringRedisTemplate template = new StringRedisTemplate();
              template.setConnectionFactory(redisConnectionFactory);
              return template;
          }
      }
      
      

注:

因为在反序列化时,做了一层重试的操作,所以对性能会有一些影响,肯定不是最优解。如果有大佬知道能怎么更有效率的解决该问题,还希望能够留言支持。谢谢

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Redis使用FastJson2JsonRedisSerializer进行序列化是一种常见的做法。通过配置RedisConfig类,可以将FastJson2JsonRedisSerializer作为RedisTemplate序列化器。在RedisConfig类中,通过@Bean注解创建了一个RedisSerializer的实例,并将其设置为RedisTemplate的keySerializer、valueSerializer、hashKeySerializer和hashValueSerializer。这样就可以使用FastJsonRedis中的数据进行序列化和反序列化了。同时,还需要注意在使用@Cacheable注解时,key属性只能传入String类型的值,因为使用了StringRedisSerializer作为key的序列化器。\[2\]\[3\] #### 引用[.reference_title] - *1* [Redis使用FastJson序列化/FastJson2JsonRedisSerializer](https://blog.csdn.net/moshowgame/article/details/83246363)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SpringBootredis使用FastJSON自定义序列化](https://blog.csdn.net/qq_37892957/article/details/89303942)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [阿里FastJson2JsonRedisSerializer.java作为内部类强化RedisConfig的序列化实现](https://blog.csdn.net/as4589sd/article/details/104214206)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清晨先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值