Spring Boot+Redis环境下如何通过AOP运行时修改@Cacheable的condition属性?
问题分析与解决方案
你尝试通过反射修改@Cacheable注解的condition属性来关闭缓存但未生效,核心原因是Spring在应用启动阶段就完成了缓存注解的元数据解析,并将这些信息缓存起来供后续切面使用。你运行时修改的是注解代理对象的属性,并不会影响Spring已经加载好的缓存执行逻辑,所以缓存依然会正常存储数据。
正确实现思路
方案1:利用condition绑定全局开关(最简方案)
无需通过AOP反射修改注解,直接在@Cacheable的condition中引用一个全局可修改的开关变量,修改变量值即可实时控制缓存开关:
- 定义缓存开关配置类:
@Component public class CacheSwitchConfig { // 全局缓存开关,默认开启 private boolean cacheEnabled = true; public boolean isCacheEnabled() { return cacheEnabled; } public void setCacheEnabled(boolean cacheEnabled) { this.cacheEnabled = cacheEnabled; } }
- 在
@Cacheable注解中引用该开关:
@Cacheable(value = "userCache", condition = "@cacheSwitchConfig.isCacheEnabled()") public User getUserById(Long id) { // 数据库查询逻辑 return userMapper.selectById(id); }
- 需要关闭缓存时,直接调用
cacheSwitchConfig.setCacheEnabled(false),后续方法调用会自动跳过缓存逻辑。
方案2:通过AOP拦截缓存方法,手动跳过缓存
如果一定要用AOP实现,可以让自定义切面优先于Spring Cache切面执行,直接干预方法流程:
@Aspect @Component @Order(Ordered.HIGHEST_PRECEDENCE) // 确保此切面比Spring Cache切面先执行 public class CacheSwitchAspect { @Autowired private CacheSwitchConfig cacheSwitchConfig; @Around("@annotation(org.springframework.cache.annotation.Cacheable)") public Object aroundCacheableMethod(ProceedingJoinPoint joinPoint) throws Throwable { // 缓存关闭时,直接执行目标方法,跳过Spring Cache逻辑 if (!cacheSwitchConfig.isCacheEnabled()) { return joinPoint.proceed(); } // 缓存开启时,交给Spring Cache切面处理 return joinPoint.proceed(); } }
这种方式直接拦截方法执行流程,比修改注解属性更可靠,彻底绕过了Spring缓存逻辑的触发条件。
原代码失效的根本原因
Spring Cache的CacheInterceptor在初始化阶段,会将@Cacheable注解中的condition、key等属性编译成可执行表达式并缓存。后续每次方法调用时,只会执行预先编译好的表达式,不会重新读取注解的属性值。你通过反射修改的注解代理对象memberValues,并不会影响Spring已缓存的表达式逻辑,所以无法达到关闭缓存的效果。
内容的提问来源于stack exchange,提问作者Ahmed Essam
相关产品推荐
相关产品推荐

