Spring Boot升级后@CachePut注解部分方法未执行数据更新
将应用从Spring Boot 1.2.6升级至3.2.3后,使用Spring Cache + Ehcache框架时出现异常:标注@CachePut的方法中,仅HANDLERLISTMAP缓存对应的方法能正常执行数据查询并刷新缓存,而USERS、HANDLERBETRIEBLISTMAP对应的方法,即使提前调用缓存清除逻辑,数据查询代码也未执行。
异常代码示例
未执行查询的方法(USERS缓存)
@CachePut(value = CacheDefinitions.USERS) @Override public Map<String, User> refreshUsers() { try { dataFileStore.clearCache(CacheDefinitions.USERS); return mappingDataRepository.getUsers().get(); // getUsers()未执行 } catch (InterruptedException | ExecutionException ex) { throw new RuntimeException(ex); } }
未执行查询的方法(HANDLERBETRIEBLISTMAP缓存)
@CachePut(value = CacheDefinitions.HANDLERBETRIEBLISTMAP) @Override public Map<String, List<String>> refreshHandlerBetriebListMap() { try { dataFileStore.clearCache(CacheDefinitions.HANDLERBETRIEBLISTMAP); return mappingDataRepository.getHandlerBetriebListMap().get(); // 未执行 } catch (InterruptedException | ExecutionException ex) { throw new RuntimeException(ex); } }
曾正常执行、后续失效的方法(HANDLERLISTMAP缓存)
@CachePut(value = CacheDefinitions.HANDLERLISTMAP) @Override public Map<String, ListAccessLists> refreshHanderListMap(){ dataFileStore.clearCache(CacheDefinitions.HANDLERLISTMAP); return proxy.getHandlerListMap(); // 未执行 }
正常执行的方法(HANDLERLISTMAP缓存)
@CachePut(value = CacheDefinitions.HANDLERLISTMAP) @Override public Map<String, ListAccessLists> refreshHanderListMap(){ dataFileStore.clearCache(CacheDefinitions.HANDLERLISTMAP); return proxy.getHandlerListMap(); // 此方法正常执行 }
可能原因及解决步骤
1. 移除冗余的手动缓存清除操作
@CachePut的核心语义是强制执行方法逻辑,再将返回值更新到缓存,无需手动调用清除缓存。Spring Boot 3.x对应的Spring Framework 6.x中,缓存拦截器的执行顺序与1.x存在差异,手动清除缓存可能与Spring Cache的内置逻辑冲突,导致方法执行被意外拦截。
直接删除dataFileStore.clearCache(...)调用,重新测试方法是否执行查询逻辑。
2. 检查异步查询的Future复用问题
未执行查询的方法均依赖mappingDataRepository返回的Future对象调用get(),如果该Repository内部对Future实例做了缓存复用,会导致get()直接返回旧结果,不会触发新的查询。
- 检查
mappingDataRepository的实现,确保每次调用getUsers()、getHandlerBetriebListMap()时,都会创建新的异步查询任务,而非复用已完成的Future实例。 - 可临时替换为同步查询逻辑,验证是否能正常触发数据查询。
3. 校验缓存名称的配置合法性
Spring Boot 3.x对缓存配置的校验更严格,若CacheDefinitions中定义的缓存名称未在Ehcache配置文件(如ehcache.xml或application.yml)中正确声明,可能导致缓存逻辑异常。
- 确认
USERS、HANDLERBETRIEBLISTMAP等缓存名称在Ehcache配置中存在,示例配置:<!-- ehcache.xml --> <cache alias="USERS"> <expiry> <ttl unit="seconds">3600</ttl> </expiry> <heap>1000</heap> </cache> <cache alias="HANDLERBETRIEBLISTMAP"> <expiry> <ttl unit="seconds">3600</ttl> </expiry> <heap>1000</heap> </cache> - 检查缓存名称是否存在拼写错误(如方法名
refreshHanderListMap中的Hander应为Handler,可能导致缓存名称匹配异常)。
4. 验证Spring AOP代理有效性
Spring Cache基于AOP实现,若方法调用未通过Spring代理对象(如内部调用this.refreshUsers()),会导致@CachePut注解失效,方法逻辑可能被跳过。
- 确保所有
@CachePut方法的调用是通过Spring容器管理的Bean实例触发,而非直接调用类内部方法。 - 可通过打印
this.getClass().getName()确认当前对象是否为Spring代理类(类名包含$Proxy或CGLIB标识)。
5. 开启调试日志定位问题
开启Spring Cache和Ehcache的调试日志,查看缓存操作的详细流程,确认@CachePut是否触发方法执行、缓存更新是否正常:
# application.yml logging: level: org.springframework.cache: DEBUG org.ehcache: DEBUG
通过日志可明确:
@CachePut拦截器是否生效- 方法执行前/后的缓存操作细节
- 是否存在缓存名称匹配错误
内容的提问来源于stack exchange,提问作者chriger

