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
自定义序列化方式
-
我们在使用官方提供的``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; } }
-
注:
因为在反序列化时,做了一层重试的操作,所以对性能会有一些影响,肯定不是最优解。如果有大佬知道能怎么更有效率的解决该问题,还希望能够留言支持。谢谢
更多推荐
所有评论(0)