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;
          }
      }
      
      

注:

因爲在反序列化時,做了一層重試的操作,所以對性能會有一些影響,肯定不是最優解。如果有大佬知道能怎麼更有效率的解決該問題,還希望能夠留言支持。謝謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章