问题描述
该项目结构采用Maven多模块构建的,各个模块之间通过各自提取的公共的无状态的pom模块进行依赖。项目开发过程中使用了spring的@CacheEvict进行缓存清理,但是最近发现有些缓存的key未被及时清理,有些是正常的,导致部分接口数据不是最新的
分析
通过搜索得出以下几个可能得原因:
- 缓存配置不共享:每个模块可能有自己的缓存配置,如果这些配置没有正确地统一或协调,可能会导致@CacheEvict在不同模块间不生效。确保所有模块共享相同的CacheManager配置。
- 命名空间不一致:在不同的模块中使用@CacheEvict时,确保缓存名称(cache name)是一致的。不一致的命名会导致清除操作无法命中正确的缓存。
- 组件扫描不全面:Spring需要扫描到使用了@CacheEvict注解的类或方法。确保每个模块的配置都正确设置了@ComponentScan或通过其他方式(如@Bean定义)将这些类纳入Spring的管理范围。
- 事务管理:在某些情况下,@CacheEvict可能需要在特定的事务上下文中执行。如果清除缓存的操作与事务管理不当配合,可能导致清除操作未被执行或回滚。
- 代理问题:确保所有模块都正确配置了Spring的代理模式(JDK动态代理或CGLIB代理),特别是当@CacheEvict方法被内部调用时,可能会绕过Spring的代理,导致缓存操作不生效。
- 缓存配置覆盖或遗漏:如果项目中使用了多级缓存配置或者继承配置,确保没有意外地覆盖了@CacheEvict相关的配置。
解决这些问题的一些建议:
统一缓存配置:在项目的公共配置模块中定义统一的缓存配置,确保所有模块引用或继承这个共同的配置。
检查和明确缓存命名:确保所有@CacheEvict注解中的value或cacheNames属性指向的是同一个缓存名称。
组件扫描配置:确保Spring的组件扫描能覆盖到所有使用了缓存注解的类。
事务管理配置:如果适用,检查事务配置,确保缓存操作在合适的事务上下文中执行。
代理模式配置:确认AOP代理配置正确,特别是对于内部方法调用的场景,可能需要确保使用的是CGLIB代理或其他合适的代理模式。
模块间依赖关系:检查并确认模块间的依赖关系正确,避免由于模块加载顺序或依赖缺失导致的问题。
根据以上提示,进行了如下排查:
- 首先检查了项目中所有使用了@CacheEvict注解的方法,并未发现异常,cacheNames和key都是一致的;
- 检查了@CacheEvict注解的方法调用的方式,未发现异常,都是通过代理模式调用非类内部调用;
- 检查了其他方面,比如网上说的返回值必须为void,必须由controller层调用,发现确实有些方法不满足条件,但却未失效,因此并不适用于我当前遇到的情况。
原因
- 经过猜想验证,发现多模块的结构下,不在同一个module中的@Cacheable和@CacheEvict注解不能相互配合创建和删除缓存。
解决
找到原因就比较好解决了,此处是通过将需要对同一cacheNames的缓存进行创建和删除操作的方法挪到同一module下,挪动后的方法通过maven依赖调用,至此问题解决。