Bug:SpringBoot整合SpringCache与Redis踩过的坑

左手的ㄟ右手 2024-04-03 08:07 183阅读 0赞

Bug:SpringBoot整合SpringCache与Redis踩过的坑

1 场景回现

今天在做项目的时候需要使用SpringCache与Redis作为缓存
但是在,配置完成后,发现并没有达到目的

1.1 无法连接到远程的Redis

  1. org.springframework.data.redis.RedisConnectionFailureException: Unable to
  2. connect to Redis;

1.2 无法实现缓存

在排查完无法连接到Redis之后,以为项目能够正常运行,结果发现前端无法访问到数据
后台直接报错

  1. Bean named**is expected to be of type**but
  2. was actually of type com.sun.proxy.$Proxy**

2 SpringBoot整合SpringCache与Redis步骤

整合步骤:

①导入依赖

  1. <!-- redis -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-redis</artifactId>
  5. </dependency>
  6. <!-- spring2.X集成redis所需common-pool2-->
  7. <dependency>
  8. <groupId>org.apache.commons</groupId>
  9. <artifactId>commons-pool2</artifactId>
  10. <version>2.6.0</version>
  11. </dependency>

②application.properties配置文件

  1. spring.redis.host=192.168.145.13
  2. spring.redis.port=6379
  3. spring.redis.database= 0
  4. spring.redis.timeout=1800000
  5. spring.redis.lettuce.pool.max-active=20
  6. spring.redis.lettuce.pool.max-wait=-1
  7. #最大阻塞等待时间(负数表示没限制)
  8. spring.redis.lettuce.pool.max-idle=5
  9. spring.redis.lettuce.pool.min-idle=0

③Redis配置类【自定义key规则、缓存规则、转换问题(序列化)】
RedisConfig:

  1. /**
  2. * @author 夏末
  3. * @description TODO
  4. * @date 2022/10/1 10:11
  5. */
  6. @Configuration
  7. @EnableCaching
  8. public class RedisConfig {
  9. /**
  10. * 自定义key规则
  11. * @return
  12. */
  13. @Bean
  14. public KeyGenerator keyGenerator() {
  15. return new KeyGenerator() {
  16. @Override
  17. public Object generate(Object target, Method method, Object... params) {
  18. StringBuilder sb = new StringBuilder();
  19. sb.append(target.getClass().getName());
  20. sb.append(method.getName());
  21. for (Object obj : params) {
  22. sb.append(obj.toString());
  23. }
  24. return sb.toString();
  25. }
  26. };
  27. }
  28. /**
  29. * 设置RedisTemplate规则
  30. * @param redisConnectionFactory
  31. * @return
  32. */
  33. @Bean
  34. public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
  35. RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
  36. redisTemplate.setConnectionFactory(redisConnectionFactory);
  37. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  38. //解决查询缓存转换异常的问题
  39. ObjectMapper om = new ObjectMapper();
  40. // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
  41. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  42. // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
  43. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  44. jackson2JsonRedisSerializer.setObjectMapper(om);
  45. //序列号key value
  46. redisTemplate.setKeySerializer(new StringRedisSerializer());
  47. redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
  48. redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  49. redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
  50. redisTemplate.afterPropertiesSet();
  51. return redisTemplate;
  52. }
  53. /**
  54. * 设置CacheManager缓存规则
  55. * @param factory
  56. * @return
  57. */
  58. @Bean
  59. public CacheManager cacheManager(RedisConnectionFactory factory) {
  60. RedisSerializer<String> redisSerializer = new StringRedisSerializer();
  61. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  62. //解决查询缓存转换异常的问题
  63. ObjectMapper om = new ObjectMapper();
  64. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  65. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  66. jackson2JsonRedisSerializer.setObjectMapper(om);
  67. // 配置序列化(解决乱码的问题),过期时间600秒
  68. RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
  69. .entryTtl(Duration.ofSeconds(600))
  70. .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
  71. .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
  72. .disableCachingNullValues();
  73. RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
  74. .cacheDefaults(config)
  75. .build();
  76. return cacheManager;
  77. }
  78. }

④在service的对应实现类中添加相应注解

  1. /**
  2. * 根据id查询子数据列表
  3. * @param id
  4. * @return
  5. */
  6. @Override
  7. @Cacheable(value = "dict",keyGenerator = "keyGenerator")
  8. public List<Dict> findChildData(Long id) {
  9. QueryWrapper<Dict> wrapper = new QueryWrapper<>();
  10. wrapper.eq("parent_id", id);
  11. List<Dict> dicts = dictMapper.selectList(wrapper);
  12. for(Dict dict : dicts){
  13. Long dictId = dict.getId();
  14. dict.setHasChildren(hasChild(dictId));
  15. }
  16. return dicts;
  17. }
  18. /**
  19. * 导入数据
  20. * allEntries = true: 方法调用后清空所有缓存
  21. */
  22. @Override
  23. @CacheEvict(value = "dict", allEntries=true)
  24. public void importDictData(MultipartFile file) {
  25. try{
  26. EasyExcel.read(file.getInputStream(), DictEeVo.class, new DictListener(dictMapper))
  27. .sheet().doRead();
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }

⑤在启动类上开启扫描(扫描RedisConfig配置类)

  1. @SpringBootApplication
  2. @EnableSwagger2
  3. @ComponentScan(basePackages = {
  4. "com.zi"})
  5. public class ServiceCmnApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(ServiceCmnApplication.class);
  8. }
  9. }

3 原因排查

3.1 无法连接到远程Redis

①配置文件端口配错
②远程Redis的保护模式打开了

  1. "修改redis.conf文件",将protected-mode配置设置为no

③bind绑定问题

  1. "redis.conf文件"bind设置为了只允许本机访问。
  2. 将该行注释,或者将项目运行的服务器地址配置上去

④设置了访问密码

  1. "redis.conf文件",在配置文件中将密码去掉或者在SpringBootapplication.yml中添加正确密码

3.2 无法实现缓存

①检查对应注解的value值是否正确
如:
Redis配置类的键生成器:
在这里插入图片描述
对应注解上的value值是否为类名首字母小写
在这里插入图片描述
②是否在配置类上开启注解,是否将配置类作为Bean交给Spring管理

  1. @Configuration
  2. @EnableCaching
  3. public class RedisConfig {
  4. ...
  5. }

③如果是多个模块的话,是否在启动类上添加了注解扫描

  1. @SpringBootApplication
  2. @EnableSwagger2
  3. @ComponentScan(basePackages = {
  4. "com.zi"})
  5. public class ServiceCmnApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(ServiceCmnApplication.class);
  8. }
  9. }

④如果是代码本身报错,查看是否是Idea自动导包导入错了

4 解决问题

无法访问到远程Redis,是因为我开启了保护模式,将其改为no即可

无法实现缓存目的是因为我的项目是多个模块,但是在启动上没有添加注解扫描,同时将注解上面的value值对应错了,修改为keyGenerator即可

发表评论

表情:
评论列表 (有 0 条评论,183人围观)

还没有评论,来说两句吧...

相关阅读

    相关 redis集群部署及

    本文目标 > 要在单台机器上搭建Redis集群,方式是通过不同的TCP端口启动多个实例,然后组成集群,同时记录在搭建过程中踩过的坑。 安装准备 > c

    相关 Redis一些-美团

    上上周和同事(龙哥)参加了360组织的互联网技术训练营第三期,美团网的DBA负责人侯军伟给大家介绍了美团网在redis上踩得一些坑,讲的都是干货和坑。     分为5个部分: