springcache缓存时,@Cacheable(key = "'by_id:' + #id") #key为null,#p0正常

问题背景

Spring Cache的键生成。@Cacheable注解中尝试使用参数名作为键,比如key = "#key",但发现缓存键为null,而改用#p0则可以正常添加key。

问题原因

  1. Java 编译默认不保留参数名
    Java 编译器在编译 .class 文件时,默认不会保留方法的参数名称(出于安全性和优化考虑)。例如:
public String getValue(String key) { ... }

编译后,参数名 key 会被丢弃,变成 arg0。此时,Spring 无法通过 #key 识别参数名。

  1. #p0#key 的区别
    #p0 是 基于参数位置的引用(第一个参数),不依赖参数名称,总能正确解析。

#key 是 基于参数名称的引用,需要依赖参数名被保留才能生效。如果参数名未保留,SpEL 会认为 key 是一个不存在的变量,导致结果为 null。

Spring Cache的工作原理

当使用@Cacheable时,Spring会根据指定的SpEL表达式生成缓存键。如果表达式引用了方法参数名,比如#key,那么Spring需要能够访问到这些参数名。然而,Java在编译时默认不会保留方法参数名称,除非使用-parameters编译选项。如果参数名不可用,SpEL可能无法解析#key,导致键为null。而#p0则是基于参数位置的引用,无论参数名是否存在,都能正确指向第一个参数,因此在这种情况下更可靠。

常见解决方案

  1. 确保编译时保留参数名,使用-parameters选项;
  2. 在IDE中配置保留参数名;
  3. 使用@Param注解显式指定参数名;
  4. 使用位置参数如#p0作为替代方案;
  5. 自定义KeyGenerator.

解决

  1. 启用编译时保留参数名
    在编译代码时,强制保留方法的参数名称。这是最彻底的解决方案。

配置方式:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <compilerArgs>
            <arg>-parameters</arg>
        </compilerArgs>
    </configuration>
</plugin>
image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容