springboot2.x使用redis作为缓存(使用fastjson序列化的方式,并调试反序列化异常

https://blog.csdn.net/qq_33999844/article/details/82182427

1.redis是内存数据库,可以单独作为数据库(有持久化方案),也可以作为缓存(一般为MySQL搭配)

       1.1 可以通过jedis,代码的方式手动将其传入redis作为缓存;

       1.2 也可以通过注解的方式,和spring boot整合,通过@cacheable...的方式自动存入redis(本文的探讨方式)

2.springboot2.x与1.x版本用法相差较大

     例如:缓存管理器的自定义方式


 
 
  1. @Bean //spring boot1.x版本的使用方式
  2. public CacheManager cacheManager(RedisTemplate redisTemplate) {
  3. RedisCacheManager cacheManager= new RedisCacheManager(redisTemplate);
  4. cacheManager.setDefaultExpiration( 60);
  5. Map<String,Long> expiresMap= new HashMap<>();
  6. expiresMap.put( "Product", 5L);
  7. cacheManager.setExpires(expiresMap);
  8. return cacheManager;
  9. }

   到了2.x版本,没有这个构造方法,该方式已经不能使用; 

3.springboot2.x使用redis作为缓存

思路:

1.编写RedisConfig配置类----配置类里面重构cacheManager和redisTemplate;  后期可以在该类中设置key的生成策略等...

2.实现对象的缓存,定义自己的序列化和反序列化器。(必须定义自己的)

   在redisConfig类中不要导入:

import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;//不要导入

   导入:

import zmc.leon.mcd.Util.FastJsonRedisSerializer;//自定义的序列化反序列化器

3.spring boot+mybatis的controller、service、dao层的编写(省略)

 

RedisConfig.java


 
 
  1. package zmc.leon.mcd.Config;
  2. //import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
  3. import com.alibaba.fastjson.parser.ParserConfig;
  4. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  5. import com.fasterxml.jackson.annotation.PropertyAccessor;
  6. import com.fasterxml.jackson.databind.ObjectMapper;
  7. import com.fasterxml.jackson.databind.SerializationFeature;
  8. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  9. import org.springframework.cache.CacheManager;
  10. import org.springframework.cache.annotation.CachingConfigurerSupport;
  11. import org.springframework.cache.annotation.EnableCaching;
  12. import org.springframework.context.annotation.Bean;
  13. import org.springframework.context.annotation.Configuration;
  14. import org.springframework.context.annotation.Primary;
  15. import org.springframework.data.redis.cache.RedisCacheConfiguration;
  16. import org.springframework.data.redis.cache.RedisCacheManager;
  17. import org.springframework.data.redis.cache.RedisCacheWriter;
  18. import org.springframework.data.redis.connection.RedisConnectionFactory;
  19. import org.springframework.data.redis.core.RedisTemplate;
  20. import org.springframework.data.redis.serializer.*;
  21. import zmc.leon.mcd.Util.FastJsonRedisSerializer;
  22. import javax.crypto.KeyGenerator;
  23. import java.lang.reflect.Method;
  24. import java.time.Duration;
  25. import java.util.HashMap;
  26. import java.util.HashSet;
  27. import java.util.Map;
  28. import java.util.Set;
  29. @Configuration
  30. @EnableCaching
  31. public class RedisConfig extends CachingConfigurerSupport {
  32. /**
  33. * 重写Redis序列化方式,使用Json方式:
  34. * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。
  35. * Spring Data JPA为我们提供了下面的Serializer:
  36. * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。
  37. * 在此我们将自己配置RedisTemplate并定义Serializer。
  38. *
  39. */
  40. // 存入redis时,默认使用的是JdkSerializationRedisSerializer,使得存入的数据全部序列化了,所需自定义一个RedisTemplate,使用其他序列化方式
  41. //当redis依赖包导入的时候,默认的cache即可自动变成redis模式;如果只是导入cache的依赖,则默认的是simpleCacheManager;
  42. // 使用redis缓存时,RedisCacheManager生成RedisCache后生成缓存时默认使用JdkSerializationRedisSerializer序列化(cache存储的时候)
  43. //当ioc容器内没有自定义的缓存管理器的时候---默认使用自带的;
  44. //当通过@Bean在ioc容器中注入了以下管理器,则会使用自定义的管理器;
  45. // @Bean
  46. // public CacheManager cacheManager(RedisConnectionFactory factory) {
  47. // RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 生成一个默认配置,通过config对象即可对缓存进行自定义配置
  48. // config = config.entryTtl(Duration.ofMinutes(1)) // 设置缓存的默认过期时间,也是使用Duration设置
  49. // .disableCachingNullValues(); // 不缓存空值
  50. //
  51. // // 设置一个初始化的缓存空间set集合
  52. // Set<String> cacheNames = new HashSet<>();
  53. // cacheNames.add("my-redis-cache1");
  54. // cacheNames.add("my-redis-cache2");
  55. //
  56. // // 对每个缓存空间应用不同的配置
  57. // Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
  58. // configMap.put("my-redis-cache1", config);
  59. // configMap.put("my-redis-cache2", config.entryTtl(Duration.ofSeconds(120)));
  60. //
  61. // RedisCacheManager cacheManager = RedisCacheManager.builder(factory) // 使用自定义的缓存配置初始化一个cacheManager
  62. // .initialCacheNames(cacheNames) // 注意这两句的调用顺序,一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
  63. // .withInitialCacheConfigurations(configMap)
  64. // .build();
  65. // return cacheManager;
  66. // }
  67. @Bean
  68. @Primary //当有多个管理器的时候,必须使用该注解在一个管理器上注释:表示该管理器为默认的管理器
  69. public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
  70. //初始化一个RedisCacheWriter
  71. RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
  72. //序列化方式1
  73. //设置CacheManager的值序列化方式为JdkSerializationRedisSerializer,但其实RedisCacheConfiguration默认就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value,所以以下(4行)注释代码为默认实现
  74. // ClassLoader loader = this.getClass().getClassLoader();
  75. // JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer(loader);
  76. // RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jdkSerializer);
  77. // RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
  78. //序列化方式1---另一种实现方式
  79. //RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();//该语句相当于序列化方式1
  80. //序列化方式2
  81. FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); //JSONObject
  82. RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer);
  83. RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
  84. //序列化方式3
  85. //Jackson2JsonRedisSerializer serializer=new Jackson2JsonRedisSerializer(Object.class);
  86. //RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(serializer);
  87. //RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
  88. defaultCacheConfig = defaultCacheConfig.entryTtl(Duration.ofSeconds( 100)); //设置过期时间
  89. // //设置默认超过期时间是30秒
  90. // defaultCacheConfig.entryTtl(Duration.ofSeconds(30));
  91. //初始化RedisCacheManager
  92. RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
  93. //设置白名单---非常重要********
  94. /*
  95. 使用fastjson的时候:序列化时将class信息写入,反解析的时候,
  96. fastjson默认情况下会开启autoType的检查,相当于一个白名单检查,
  97. 如果序列化信息中的类路径不在autoType中,
  98. 反解析就会报com.alibaba.fastjson.JSONException: autoType is not support的异常
  99. 可参考 https://blog.csdn.net/u012240455/article/details/80538540
  100. */
  101. ParserConfig.getGlobalInstance().addAccept( "zmc.leon.mcd.entity.");
  102. return cacheManager;
  103. }
  104. /**
  105. * 设置 redis 数据默认过期时间
  106. * 设置@cacheable 序列化方式
  107. * @return
  108. */
  109. @Bean
  110. public RedisCacheConfiguration redisCacheConfiguration(){
  111. FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
  112. RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
  113. configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofDays( 30));
  114. return configuration;
  115. }
  116. @Bean(name = "redisTemplate")
  117. @SuppressWarnings( "unchecked")
  118. @ConditionalOnMissingBean(name = "redisTemplate")
  119. public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
  120. RedisTemplate<Object, Object> template = new RedisTemplate<>();
  121. //使用fastjson序列化
  122. FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
  123. // value值的序列化采用fastJsonRedisSerializer
  124. template.setValueSerializer(fastJsonRedisSerializer);
  125. template.setHashValueSerializer(fastJsonRedisSerializer);
  126. // key的序列化采用StringRedisSerializer
  127. template.setKeySerializer( new StringRedisSerializer());
  128. template.setHashKeySerializer( new StringRedisSerializer());
  129. template.setConnectionFactory(redisConnectionFactory);
  130. return template;
  131. }
  132. // @Bean
  133. // public KeyGenerator KeyGenerator() {
  134. // return new KeyGenerator(){
  135. // public Object generate(Object target, Method method, Object... params) {
  136. // StringBuilder sb = new StringBuilder();
  137. // sb.append(target.getClass().getName());
  138. // sb.append(method.getName());
  139. // for (Object obj : params) {
  140. // sb.append(obj.toString());
  141. // }
  142. // return sb.toString();
  143. // }
  144. // };
  145. // }
  146. }

FastJsonRediaSerializer.java


 
 
  1. package zmc.leon.mcd.Util;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.serializer.SerializerFeature;
  4. import org.springframework.data.redis.serializer.RedisSerializer;
  5. import org.springframework.data.redis.serializer.SerializationException;
  6. import java.nio.charset.Charset;
  7. /*
  8. 要实现对象的缓存,定义自己的序列化和反序列化器。使用阿里的fastjson来实现的比较多。
  9. */
  10. public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
  11. private static final Charset DEFAULT_CHARSET = Charset.forName( "UTF-8");
  12. private Class<T> clazz;
  13. public FastJsonRedisSerializer(Class<T> clazz) {
  14. super();
  15. this.clazz = clazz;
  16. }
  17. @Override
  18. public byte[] serialize(T t) throws SerializationException {
  19. if ( null == t) {
  20. return new byte[ 0];
  21. }
  22. return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
  23. }
  24. @Override
  25. public T deserialize(byte[] bytes) throws SerializationException {
  26. if ( null == bytes || bytes.length <= 0) {
  27. return null;
  28. }
  29. String str = new String(bytes, DEFAULT_CHARSET);
  30. return (T) JSON.parseObject(str, clazz);
  31. }
  32. }

 

注意:

1.一定要导入自己的util包

import zmc.leon.mcd.Util.FastJsonRedisSerializer;

2.缓存管理器中一定要加入(白名单),其中的包名:为自己的bean类的所在包

ParserConfig.getGlobalInstance().addAccept("zmc.leon.mcd.entity.");

没有的话会有以下异常:

com.alibaba.fastjson.JSONException: autoType is not support

 

具体解释请关注:

https://blog.csdn.net/u012240455/article/details/80538540

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值