Spring缓存:生成缓存键时忽略可选参数的实现方法
解决@Cacheable忽略可选user-agent参数生成缓存键的方法
嘿,这个场景我经常碰到!要让Spring的@Cacheable生成缓存键时跳过那个可选的user-agent参数,有几个实用的方案,我给你一一拆解:
方案1:直接用SpEL指定缓存键(最简单)
如果你的方法里只有user-agent这一个参数,或者你明确知道哪些参数需要纳入缓存键,直接在@Cacheable的key属性里写死或者指定需要的参数就行。比如:
@Cacheable(value="bookCache", key = "'all-books'") public Book getBooks(@RequestHeader(value = "user-agent", required = false) String userAgent) { // 方法逻辑 }
要是方法还有其他需要区分缓存的参数(比如bookId),就把这些参数加入key,完全忽略user-agent:
@Cacheable(value="bookCache", key = "#bookId") public Book getBooks(String bookId, @RequestHeader(value = "user-agent", required = false) String userAgent) { // 方法逻辑 }
这种方式适合单个方法的简单场景,不用额外写代码。
方案2:自定义KeyGenerator(灵活通用)
如果你有多个方法都需要忽略user-agent参数,自定义一个全局的KeyGenerator会更高效。步骤如下:
1. 实现自定义KeyGenerator
import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @Component("ignoreUserAgentKeyGenerator") public class IgnoreUserAgentKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { // 获取方法的所有参数名称 List<String> paramNames = Arrays.stream(method.getParameters()) .map(param -> param.getName()) .collect(Collectors.toList()); // 过滤掉名为userAgent的参数值 List<Object> filteredParams = Arrays.stream(params) .filter((param, index) -> !"userAgent".equals(paramNames.get(index))) .collect(Collectors.toList()); // 用类名、方法名+过滤后的参数生成唯一缓存键 return target.getClass().getSimpleName() + "_" + method.getName() + "_" + filteredParams; } }
2. 开启参数名编译支持
要让method.getParameters().getName()能正确获取参数名,需要在编译时开启参数名保留。比如Maven的pom.xml里配置:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <!-- 对应你的JDK版本 --> <target>1.8</target> <compilerArgs> <arg>-parameters</arg> <!-- 关键参数 --> </compilerArgs> </configuration> </plugin> </plugins> </build>
3. 在@Cacheable中使用自定义KeyGenerator
@Cacheable(value="bookCache", keyGenerator = "ignoreUserAgentKeyGenerator") public Book getBooks(@RequestHeader(value = "user-agent", required = false) String userAgent) { // 方法逻辑 }
方案3:用SpEL排除指定位置的参数
如果user-agent是方法的第一个参数,也可以通过#root.args来排除它。比如方法只有这一个参数时:
@Cacheable(value="bookCache", key = "'static-key'")
如果有多个参数,比如user-agent是第一个,第二个是bookType,就用:
@Cacheable(value="bookCache", key = "#root.args[1]")
这种方式适合参数位置固定的场景,但可读性不如前两种,参数位置变化时容易出错。
内容的提问来源于stack exchange,提问作者hansi
相关产品推荐
相关产品推荐

