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

Spring Boot 2.5.12 内存缓存@Cacheable使用与问题排查

Spring Boot 内存缓存配置问题解决方案(基于2.5.12版本)

问题1:使用account ID作为缓存key的配置方式

@Cacheable的key属性支持SpEL表达式直接读取参数属性,配置方式如下:

@Cacheable(cacheNames = "products", key = "#account.id")
public Product getProduct(AccountDetails account){
    return configProduct.getProduct(account.getId());
}

其中#account对应方法入参的account对象,.id即读取该对象的id字段作为缓存key。

问题2:配置cacheNames、key属性报错的原因

出现该问题100%是注解导错包:

  • Spring原生缓存注解的全限定名为org.springframework.cache.annotation.Cacheable,该注解中value和cacheNames是互为别名的属性,二者效果完全一致,同时原生支持key属性配置。
  • 如果导入了其他框架、自定义封装的同名@Cacheable注解,就会出现属性不匹配、仅能识别value属性的问题,把导包替换为Spring原生注解即可解决。

问题3:缓存刷新实现方案(支持同方法实现)

缓存刷新的本质是先删除旧缓存,再执行方法拉取新值写入缓存,有两种常用实现:

方案1:独立方法实现(逻辑更清晰)

用@CacheEvict完成缓存剔除,再封装刷新逻辑调用查询方法即可自动写入新缓存:

// 剔除指定key的缓存,方法内不需要写业务逻辑
@CacheEvict(cacheNames = "products", key = "#account.id")
public void clearProductCache(AccountDetails account) {}

// 刷新缓存
public Product refreshProduct(AccountDetails account) {
    clearProductCache(account);
    // 清除缓存后调用查询方法,会直接执行外部Jar调用逻辑,将新结果写入缓存
    return getProduct(account);
}

方案2:同一方法内实现刷新

给方法增加一个布尔类型的刷新控制参数,通过condition属性搭配@Cacheable和@CachePut注解实现:

// refresh为true时走@CachePut逻辑:直接执行方法,将结果更新到缓存
// refresh为false时走@Cacheable逻辑:优先查缓存,缓存不存在再执行方法
@CachePut(cacheNames = "products", key = "#account.id", condition = "#refresh")
@Cacheable(cacheNames = "products", key = "#account.id", condition = "!#refresh")
public Product getProduct(AccountDetails account, boolean refresh){
    return configProduct.getProduct(account.getId());
}

调用时传入refresh=true即可强制刷新缓存,传入false则走正常缓存逻辑。

缓存不生效排查&缓存值验证方法

常见不生效原因

  • 启动类未加@EnableCaching注解,缓存注解默认不会生效
  • 存在类内自调用:@Cacheable基于Spring AOP代理实现,同一个类中直接调用方法不会走代理逻辑,必须通过Spring注入的Bean实例调用方法才能触发缓存
  • key匹配问题:未自定义key时,默认的SimpleKeyGenerator会将所有入参拼接作为key,如果AccountDetails类未实现equals方法,可能导致key匹配失败

验证缓存是否写入

Spring Boot默认内存缓存底层为ConcurrentMapCache,可直接注入CacheManager查看缓存内容:

@Autowired
private CacheManager cacheManager;

public void checkCache(AccountDetails account) {
    Cache productCache = cacheManager.getCache("products");
    // 获取指定key的缓存值
    Product cachedValue = productCache.get(account.getId(), Product.class);
    if (cachedValue != null) {
        System.out.println("缓存命中,值为:" + cachedValue);
    } else {
        System.out.println("对应key无缓存");
    }
}

最简验证方式:在getProduct方法内部加一行打印日志或打端点,连续两次调用方法,如果第二次调用没有进入方法内部、没有触发日志/断点,说明缓存正常生效;如果每次都进入方法,按照上述不生效原因逐一排查即可。


内容的提问来源于stack exchange,提问作者Sajal Saxena

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 22:15:31