qinghuan
← 缓存的操作与结果目录

SPRING CACHE / 补充讲义 7 / 7

异步缓存的完成值与流式边界验收

检查 Future 完成值、有限 Flux 列表及异步缓存实现的前提。

异步查询先返回 Future,稍后才产生商户结果。验收缓存时,应比较完成后的业务值与加载次数,不能只比较两个 Future 是否为同一对象。流式输出还要进一步区分完整结果缓存与逐条回放。

资料基于 Spring Framework 7.0.10。原始核查:2026 年 10 月 26 日;发布整理复核:2026 年 10 月 30 日 JST。以下 Java 与 Reactor 练习尚未运行;本节只讨论正常完成的非空值与有限流。

缓存适配面向产出的结果

返回 CompletableFuture 的方法,缓存适配面向 Future 完成后产出的对象;命中时仍通过 Future 返回结果。Mono 缓存产出的值,Flux 则把元素收集为 List,完整后缓存。异步与响应式缓存指南

因此,给 token 流添加 @Cacheable 不能推出“每产生一个 token 就留下一个可恢复增量”。完整结果缓存与流式回放应分别设计。官方也提醒:包含复杂组合与背压的响应式交互,不适合简单套用注解缓存。

缓存实现也要支持异步取值

配置的缓存需要支持基于 CompletableFuture 的取值。指南说明 ConcurrentMapCacheManager 会自动适配;CaffeineCacheManager 默认构建普通缓存,启用异步模式通常需要 setAsyncCacheMode(true)。

自定义注册的缓存不由这个开关自动转换,仍须检查实际类型。CaffeineCacheManager API与固定版本实现明确区分通用配置与自定义注册。

最小配置片段

以下片段放在已经启用缓存的测试配置与受代理 Bean 中,依赖版本由构建文件固定。假 repository 返回可手动完成的 Future;暂不叠加事务、重试或 sync,以便分清观测对象。省略的类型、导入和测试夹具需要由练习提供。

文中示例 · java
@Bean
CacheManager cacheManager() {
    var manager = new CaffeineCacheManager("shopsAsync");
    manager.setAsyncCacheMode(true);
    return manager;
}

@Cacheable(cacheNames = "shopsAsync", key = "#p0")
public CompletableFuture<ShopView> findAsync(long id) {
    return repository.findAsync(id);
}

练习一:完成前与完成后分别观察

假 repository 返回未完成 Future,并记录实际调用次数。首次经代理调用后,确认调用方结果尚未完成;手动完成为非空 ShopView,再等待首次结果完成。之后发起同键第二次调用,检查返回业务值相等且 repository 计数仍为 1。

记录结果完成时间,不把返回 Future 的时间当成查询完成时间,也不从这个实验推断底层缓存此前完全没有占位或 Future 条目。并发未命中去重另按已有同键加载章节设计。

练习二:有限流与尚未结束的流

只在已使用 Reactor 的隔离测试中,令有限 Flux 依次发出三条假商户视图并正常完成,再核验命中后按同序返回三条。

另设一个可手动终止的测试流:已经发出元素,但暂不完成。此时不能据此宣布完整列表结果已经缓存。测试应设有限超时并在结束时清理订阅,不接入真实 token 服务,也不必为本题迁移现有 MVC 项目。

后续还需哪些验收

返回 Future 不代表后台工作完成,缓存适配也不提供背压或分布式去重保证。异常完成、取消、空值、容量与内存上界需另行测试,不能由有限流推断无限流可缓存。

setAsyncCacheMode 的 Since 6.1 是 API 起始版本;来源独立发布日期未标明。现有 6.2.11 项目的完整依赖兼容性未验证。取消与迟到结果可以继续阅读工具取消验收。