前言
在我們項目進行開發時,不可避免的會使用到Redis,Spring官方給我們提供了RedisTemplate
這個類,它替我們封裝提供了Redis基本上全部的常用操作。而官方默認使用的序列化方式爲Sdk提供的序列化類。下面講如何替換SpringBoot默認序列化方式,並解決一些問題
依賴版本
SpringBoot版本:2.2.6
SpringBoot-redis-starter版本:2.2.6
FastJson版本:1.2.68
JDK:1.8
自定義序列化方式
-
我們在使用官方提供的``FastJsonRedisSerializer`時,從Redis取回的數據,爲JSONObject或JSONArray類型,需要手動轉換成自己需要的實體。
-
官方還提供了另外一個
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); } } }
-
自定義序列化類:
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); } } }
-
新建
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; } }
-
注:
因爲在反序列化時,做了一層重試的操作,所以對性能會有一些影響,肯定不是最優解。如果有大佬知道能怎麼更有效率的解決該問題,還希望能夠留言支持。謝謝