Supplier在Caffeine中仅负责惰性计算一次,不处理加载失败;失败时需手动封装兜底逻辑,如返回Optional、默认值或结合熔断器。

Supplier 在 Caffeine 中不直接承担“加载失败时的回底策略”职责,它只是提供一个无参、惰性求值的值生成逻辑。真正决定加载失败后行为的是 缓存构建方式 和 调用上下文 —— Supplier 本身不会重试、兜底或降级,它只负责“算一次”。是否兜底、怎么兜底,得靠你把它嵌套在更上层的逻辑里。
Supplier 通常出现在 get(key, Supplier) 场景中
这是最常见也最容易误解的用法:
- cache.get(key, () -> fetchFromDB(key)):当 key 不存在时,Caffeine 会原子地执行该 Supplier,并把返回值写入缓存后返回
- 但如果 fetchFromDB(key) 抛出异常(如 SQLException、TimeoutException),整个 get() 调用就会直接抛出该异常,不会缓存 null,也不会自动重试,更不会 fallback 到默认值
- 也就是说:Supplier 执行失败 = 整个缓存访问失败,调用方必须自己捕获并处理
想实现真正的“失败兜底”,得手动封装 Supplier
不能依赖 Caffeine 自动做,必须由你控制异常流。常见做法是把 Supplier 改造成“带兜底的 Supplier”:
- 返回 Optional:Supplier<Optional<String>>,内部捕获异常后返回 Optional.empty()
- 返回默认值:() -> { try { return fetchFromDB(key); } catch (Exception e) { log.warn("DB load failed for {}", key, e); return "DEFAULT_VALUE"; } }
- 委托给 Resilience4j 或 Sentinel:用 CircuitBreaker.decorateSupplier(...) 包一层,实现熔断+fallback
LoadingCache 的 Supplier 行为更严格
如果你用的是 LoadingCache(build(loader) 方式),loader 参数本质是 Function<K, V>,不是 Supplier。它的语义是“必须返回有效值”,一旦抛异常:
立即学习“Java免费学习笔记(深入)”;
- 当前 get(key) 调用失败(抛出 ExecutionException 包装原异常)
- 该 key 不会被缓存(entry 不写入)
- 下次再 get 同样 key,仍会再次触发 loader —— 无自动重试,无 fallback,无静默降级
异步场景下 Supplier 更需谨慎
AsyncLoadingCache 的 loader 是 AsyncFunction<K, V>,返回 CompletableFuture。此时 Supplier 类似的逻辑若抛异常:
- CompletableFuture 会以该异常完成(.exceptionally 可捕获)
- 但 Caffeine 不会自动 fallback;你需要显式 .handle((v, t) -> t != null ? DEFAULT : v) 或类似链式处理
- 否则上游调用 get(key).join() 仍会抛出 CompletionException

















