Spring Cache缓存方法疑似被绕过?后端请求异常频繁求助排查
问题排查与解决方案
核心原因分析
你遇到的问题核心在于缓存的对象是惰性求值类型(如Reactive的Flux/Mono),而非实际数据集合:
- Web应用的
getFooBars方法被@Cacheable缓存后,确实只执行一次(所以每15分钟才打印一次"CACHE MISS"),但方法返回的是WebClient请求得到的Flux或Mono这类Reactive容器对象,而非直接返回数据集合。 - Thymeleaf每次渲染页面调用
toIterable()时,都会触发Reactive容器的订阅操作,导致WebClient重新发起HTTP请求到后端服务,所以后端每次刷新都打印"backend getting foobars"。
排查验证步骤
- 打印
getFooBars方法返回值的哈希码:在方法内添加System.out.println("返回对象哈希码:" + result.hashCode());,确认缓存命中时返回的是同一个对象。 - 检查返回类型:确认
getFooBars的返回值是否为Flux<FooBar>、Mono<List<FooBar>>这类惰性类型,而非List<FooBar>这类直接的数据集合。
解决方案
修改getFooBars方法,将Reactive类型转换为实际的非惰性数据集合后再返回,确保缓存的是最终数据而非容器:
@Cacheable("foobar") public List<FooBar> getFooBars() { System.out.println("CACHE MISS"); // 将WebClient的Reactive结果转换为实际List return webClient.get() .uri("/api/foobars") .retrieve() .bodyToFlux(FooBar.class) .collectList() // 收集为List .block(); // 阻塞获取结果(适配Thymeleaf同步渲染场景) }
同时修改Thymeleaf表达式,直接遍历List即可:
<th:block th:each="fooBar : ${@fooBarRepository.getFooBars}"> <!-- 渲染逻辑 --> </th:block>
其他排查方向
- 确认Spring Cache代理生效:检查
WebAppFooBarRepositoryImpl是否被Spring管理(如添加@Repository/@Component注解),且没有被内部方法调用绕过代理。 - 验证Coffee Boots配置:确认
foobar缓存的过期策略是否正确应用(从"CACHE MISS"频率来看,配置已生效)。
内容的提问来源于stack exchange,提问作者Garret Wilson
相关产品推荐
相关产品推荐

