前几个月在公司的老项目里,封装了一个统一缓存,使用Cacheable注解方案,并安排上线了。
这周增加了一个缓存命中率的统计数据,发现有些场景的缓存命中率为0,太奇怪了。

1、在本地调试了一下,可以重现。
出问题的代码如下:

@FeignClient(url = xxx)
public interface XxxService {@PostMapping("/refresh/checkVpsStatus")@Cacheable(value = "aaa", key = "'vpsStatus:' + #instanceId")ResponseData checkVpsStatus(String instanceId);

其它的代码,都是class,而不是interface,功能都正常,也就是只有interface才有问题。

2、接着做代码跟踪,跟到CacheAspectSupport.generateKey方法时,发现
Object key = context.generateKey(result);得到的key为 vpsStatus:null
也就是问题出现没获取到调用的形参instanceId的值,从而读取缓存失败了。

3、进一步跟踪,解析spel表达式过程都正常,最后发现,在获取Method的形参参数名时出了问题,
在类PrioritizedParameterNameDiscoverer里有一段代码:

public String[] getParameterNames(Method method) {for (ParameterNameDiscoverer pnd : this.parameterNameDiscoverers) {String[] result = pnd.getParameterNames(method);if (result != null) {return result;}}return null;
}

跟踪到这里时,this.parameterNameDiscoverers有2个实例,分别是:

  • StandardReflectionParameterNameDiscoverer
  • LocalVariableTableParameterNameDiscoverer
    这2个类实例,都是去读取Method的参数名的,但是都返回null,取不到。

4、接着用class这种能正常读取缓存的代码,验证了一下,发现
LocalVariableTableParameterNameDiscoverer里能正常读取到class.Method的形参参数名
cacheable + LocalVariableTableParameterNameDiscoverer 搜索了一下,
说是要在Javac增加 -parameters 编译参数就可以读取到接口的形参名
于是在Idea里,配置了一下编译参数,再运行项目,果然OK了:

5、截止这里,问题清楚了,编译时,默认会擦除interface的形参名,
难道要我去配置Jenkins的构建参数吗?

去官网查了一下
https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/
发现那边明明白白写着,spring-boot已经支持了 -parameters 参数了:

3. Using the Plugin
Maven users can inherit from the spring-boot-starter-parent project to obtain sensible defaults. The parent project provides the following features:
Java 1.8 as the default compiler level.
UTF-8 source encoding.
Compilation with -parameters.

我这个老项目也是SpringBoot的啊,为啥会不行呢?
于是新建了一个项目,工作都是正常的啊。
接着比对新建项目和老工程,发现了差异点:
老项目居然只是在<dependencies>里引用了spring-cloud相关库,而没有通过<parent>去继承

6、最终解决,在老项目的pom.xml里,加上继承关系就好了

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.12</version><relativePath/> <!-- lookup parent from repository -->
</parent>

补充:
即使没有继承关系,也可以通过索引方式访问方法的参数,参考官网说明:

Method arguments can be accessed by index. For instance the second argument can be accessed via #root.args[1],
#p1 or #a1. Arguments can also be accessed by name if that information is available.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/cache/annotation/Cacheable.html

SpringBoot的Cacheable缓存问题一则相关推荐

  1. SpringBoot的Cacheable缓存入门

    因为工作需要,最近开始学习SpringBoot.要使用缓存,就搜索了下SpringBoot的缓存方案,有自带的ConcurrentLinkedHashMap,还有主流的Guava.Caffeine.E ...

  2. SpringBoot @Cacheable缓存入门程序

    导语 在之前的博客中分享了关于SpringBoot缓存的一些基本的概念,在这篇博客中提供一个小小的入门的实例,通过这个实例可以更好的了解关于SpringBoot缓存有关的知识点.   首先既然是缓存的 ...

  3. 16课:关于Springboot和@Cacheable注解拉去缓存,@CacheEvict清空缓存的原理

    16课:关于Springboot和@Cacheable注解拉去缓存,@CacheEvict清空缓存的原理 简介 代码展示 1.pox.xml 2.application.properties文件 3. ...

  4. SpringBoot集成Cache缓存(Ehcache缓存框架,注解方式)

    1.说明 Spring定义了CacheManager和Cache接口, 用来统一不同的缓存技术, 例如JCache,EhCache,Hazelcast,Guava,Redis等. 本文通过Spring ...

  5. SpringBoot与Redis缓存

    SpringBoot与Redis缓存: 准备 在Docker安装Redis 连接成功 对于Redis不熟悉的同学可以在本站搜索Redis的文章阅读. 整合Redis 在pom文件中加入 12345 & ...

  6. Springboot2.x集成ecache3.8.1使用@Cacheable缓存(代码方式,无xml)

    文章目录 前言 一.引入相关依赖 二.配置类 三. 原理说明 四.使用 前言 EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvid ...

  7. SpringBoot整合Redis缓存

    SpringBoot整合Redis缓存 一.缓存概念知识 1.是什么缓存 2.缓存的优缺点 3.为什么使用缓存 二.Redis概念知识 1.Redis简介 2.为什么用Redis作为缓存 3.Redi ...

  8. 详细SpringBoot教程之缓存开发

    写在前面 这一系列的博文初步都定下来包括SpringBoot介绍.入门.配置.日志相关.web开发.数据访问.结合docker.缓存.消息队列.检索.任务安全.分布式等等一系列的博文,工作量很大,是个 ...

  9. 七十六、SpringBoot 的数据缓存cache+Redis(三)

    @Author:Runsen 来源:尚硅谷 下面建议读者学习尚硅谷的B站的SpringBoot视频,我是学雷丰阳视频入门的. 具体链接如下:B站尚硅谷SpringBoot教程 文章目录 Redis P ...

最新文章

  1. this.name=name;和this.setName(name);的区别
  2. 【前端开发与项目管理】
  3. 资源分享 | 统计学最全思维导图,附下载链接
  4. 斜率优化Convex Hull Trick
  5. 进击的Objective-C--------Objective-C基础(-)
  6. php获取location,php获取header[‘location’]信息常见问题
  7. Android之shape属性详解
  8. 三星Galaxy Note10系列带壳渲染图曝光:将取消3.5mm耳机孔
  9. «构建并破坏它»:某些算法如何生成验证码,而另一些则如何破解
  10. 集合竞价选股(附源码)
  11. java 整理快捷键_idea快捷键整理
  12. ntfs格式硬盘如何读写mac苹果电脑
  13. 伊通一中2021高三高考成绩查询,吉林四平最好的4所高中,第1名一骑绝尘,看看有没有你的母校?...
  14. 驱动仿真物品移动乌龟\Gazebo\cmd_vel和/gazebo/set_model_state
  15. Python使用阿里API进行情感分析
  16. 机械臂抓取学习笔记二
  17. CF446D. DZY Loves Games
  18. 应用程序.f/q(f了个墙)
  19. 洛谷P3975 - [TJOI2015]弦论
  20. WinXP系统浏览器字体大小怎么调--win7w.com

热门文章

  1. 不懂人情世故就是垃圾
  2. 天馈线驻波比测试 频谱分析 干扰定位?这一款机器足以应对!
  3. Java对接Zebra斑马打印机打印条形码相关
  4. UE4 脚部IK实现
  5. 马的哈密尔顿回路(骑士周游)问题(+贪心优化)
  6. 适合女生的蓝牙耳机有哪些?四款高颜值蓝牙耳机推荐
  7. Linux 文件 常用命令
  8. html语言怎么改变文字大小,如何设置css中字体大小?
  9. 逆袭Futter? Facebook 发布全新跨平台引擎 Hermes!
  10. 每日新闻 | 旷视印奇发布公开信:人工智能必将造福所有人