Spring Boot多缓存键生成与@CacheEvict调用失效问题
问题1:生成与@Cacheable匹配的缓存键
当你在@Cacheable中指定key = "{#id, #name}"时,这个SpEL表达式会生成一个包含id和name的List<Object>对象作为缓存键(指定key属性后会跳过默认的SimpleKeyGenerator,因此直接用SimpleKey无法匹配)。以下是几种可靠的解决方案:
手动构造匹配的List对象
直接创建和SpEL表达式结果一致的List,作为驱逐的键:Long id = 123L; String name = "abc"; List<Object> cacheKey = Arrays.asList(id, name); cacheManager.getCache("cache_name").evict(cacheKey);用SpEL解析器生成键
通过Spring的SpEL解析器直接计算key表达式,确保和@Cacheable中的生成逻辑完全一致,适合复杂表达式场景:@Autowired private SpelExpressionParser spelParser; // 生成键 Long id = 123L; String name = "abc"; EvaluationContext context = new StandardEvaluationContext(); context.setVariable("id", id); context.setVariable("name", name); Object cacheKey = spelParser.parseExpression("{#id, #name}").getValue(context); cacheManager.getCache("cache_name").evict(cacheKey);针对SimpleKey场景的适配
如果你的缓存实现使用SimpleKey作为键(比如未指定key属性时的默认逻辑),需要构造参数类型完全匹配的SimpleKey:SimpleKey cacheKey = new SimpleKey(id, name); cacheManager.getCache("cache_name").evict(cacheKey);
问题2:同一服务内调用@CacheEvict方法无效
这是因为Spring缓存注解基于AOP代理实现,同一类内的方法调用不会经过代理对象,导致注解逻辑无法触发。以下是几种解决思路:
通过代理对象调用方法
在类中注入自身的代理对象,通过代理调用带@CacheEvict的方法:@Service(proxyMode = ScopedProxyMode.TARGET_CLASS) public class MyService { @Autowired private MyService selfProxy; public void businessMethod(Long id, String name) { // 通过代理对象调用缓存驱逐方法 selfProxy.evictCache(id, name); } @CacheEvict(value = "cache_name", key = "{#id, #name}") public void evictCache(Long id, String name) { // 无需业务逻辑,注解会处理缓存驱逐 } }从ApplicationContext获取代理对象
如果不想注入自身,可以通过上下文获取代理实例:@Service public class MyService { @Autowired private ApplicationContext context; public void businessMethod(Long id, String name) { MyService proxy = context.getBean(MyService.class); proxy.evictCache(id, name); } @CacheEvict(value = "cache_name", key = "{#id, #name}") public void evictCache(Long id, String name) { } }直接使用CacheManager驱逐
采用问题1中的方案,手动生成缓存键后通过CacheManager直接驱逐,无需依赖注解:public void businessMethod(Long id, String name) { List<Object> cacheKey = Arrays.asList(id, name); cacheManager.getCache("cache_name").evict(cacheKey); }
内容的提问来源于stack exchange,提问作者SLyHuy
相关产品推荐
相关产品推荐

