Spring缓存注解自调用失效求助:@CachePut不生效问题排查
问题根源与解决方案
这问题我之前踩过坑!核心原因是Spring缓存注解依赖AOP代理实现,而同一个类内部的方法调用并不会触发AOP代理逻辑——说白了,你直接调用类里的方法时,是在操作原始对象,代理类根本没机会介入,自然@CachePut的缓存更新逻辑就没执行。
为什么跨类调用就正常?
当你把方法移到其他服务类,调用时是通过Spring容器注入的Bean(也就是代理对象)来调用方法,这时候AOP代理会拦截方法调用,执行@CachePut对应的缓存更新操作,所以缓存就生效了。
解决办法
这里给你几个常用的方案,按需选择:
1. 拆分方法到独立Bean(最推荐)
就是你已经试过的方式,把带@CachePut的方法抽成单独的Service类,符合单一职责原则,代码也更清晰。比如:
// 新的缓存操作服务类 @Service public class CacheOperationService { @CachePut(value = "userCache", key = "#user.id") public User updateUserCache(User user) { // 业务逻辑:更新数据库等 return user; } } // 原服务类 @Service public class UserService { @Autowired private CacheOperationService cacheOpService; public void updateUser(User user) { // 通过注入的Bean调用,触发代理 cacheOpService.updateUserCache(user); } }
2. 自注入当前Bean(适合不想拆分的场景)
在当前类中注入自己的代理对象,然后通过这个代理对象调用带注解的方法,这样就能触发AOP逻辑。注意要加@Lazy避免循环依赖:
@Service public class UserService { // 自注入代理对象,@Lazy解决循环依赖 @Autowired @Lazy private UserService selfProxy; public void updateUser(User user) { // 调用代理对象的方法,触发@CachePut selfProxy.updateUserCache(user); } @CachePut(value = "userCache", key = "#user.id") public User updateUserCache(User user) { // 业务逻辑 return user; } }
3. 通过ApplicationContext获取代理对象
如果不想自注入,也可以从Spring容器中直接获取当前Bean的代理实例:
@Service public class UserService implements ApplicationContextAware { private ApplicationContext context; @Override public void setApplicationContext(ApplicationContext context) throws BeansException { this.context = context; } public void updateUser(User user) { // 获取代理对象并调用方法 UserService proxy = context.getBean(UserService.class); proxy.updateUserCache(user); } @CachePut(value = "userCache", key = "#user.id") public User updateUserCache(User user) { // 业务逻辑 return user; } }
4. 改用AspectJ静态代理
如果上述动态代理的方式都不满足,你可以开启AspectJ的编译时或加载时织入,这样不需要依赖Spring的动态代理,直接在字节码层面织入缓存逻辑。需要做两步:
- 开启AspectJ支持:在
@EnableCaching注解中设置mode = AdviceMode.ASPECTJ - 引入AspectJ相关依赖,并配置编译时织入(比如Maven插件)或者加载时织入
不过这个方案配置稍复杂,一般推荐前两种更简单的方式。
内容的提问来源于stack exchange,提问作者venugopal
相关产品推荐
相关产品推荐

