You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux集成Caffeine缓存:@Cacheable未缓存Mono发射值的问题及相关疑问

Spring WebFlux集成Caffeine缓存:@Cacheable未缓存Mono发射值的问题及相关疑问

咱们先理清楚你遇到的核心问题:用@Cacheable注解标注返回Mono的方法时,缓存的居然是Mono对象本身,而不是它最终发射的实际字符串值——这就导致每次从缓存取出Mono后,订阅它还是会触发原始的infoProvider.getInfo(id)调用,完全没起到缓存数据的作用。我来给你拆解问题原因、解决办法,还有你关心的为什么直接加.cache()行不通。

一、问题根源:用错了缓存启用注解

你大概率是在配置类上用了普通的@EnableCaching注解,但这个注解是给同步方法设计的!它根本不理解Reactive类型(Mono/Flux)的特性,只会把返回的Mono实例当作普通对象缓存起来,完全不会去订阅它获取实际值。

二、正确的解决步骤

要让@Cacheable正确缓存Mono发射的实际值,只需要做一个关键调整,再配合你的现有配置即可:

  1. 替换缓存启用注解
    把配置类上的@EnableCaching换成@EnableReactiveCaching——这是Spring专门为Reactive场景提供的缓存启用注解,它会自动适配Mono/Flux类型,帮你订阅Reactive流、提取实际值并缓存,而不是缓存流本身。

    举个简单的配置类例子:

    @Configuration
    @EnableReactiveCaching
    public class CacheConfig {
    }
    
  2. 保留现有配置与业务代码
    你当前的application.yml配置是完全没问题的,业务方法上的@Cacheable(value = "stuff")也不需要改。调整后,当你第一次调用getInfo(1)时,Spring会自动订阅infoProvider.getInfo(1)得到实际字符串,把这个字符串缓存到Caffeine的stuff缓存中;后续再调用同一个id的请求时,会直接从缓存取出字符串包装成Mono返回,不会再触发原始的数据源调用。

三、为什么直接加.cache()行不通?

你之前想的return infoProvider.getInfo(id).cache(),本质上是Mono自身的实例级局部缓存,和Spring Cache的全局缓存完全不是一回事,有两个核心问题:

  • 缓存范围仅限当前Mono实例:每次调用getInfo(id)都会创建一个全新的Mono对象,它的.cache()缓存只对这个实例有效。下次再调用getInfo(id),又会生成新的Mono,还是会去调用infoProvider.getInfo(id),根本没用到全局缓存。
  • 没有全局缓存策略支持:Mono的.cache()只能简单缓存值,无法实现你配置的maximumSize=1000、expireAfterAccess=3600s这类全局缓存规则,完全满足不了生产环境的缓存管控需求。

所以这种方式不仅解决不了你的问题,还会让你误以为已经缓存了数据,实际上每次请求还是会走原始数据源。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 11:38:01