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

Spring整合Caffeine实现缓存刷新失败时返回旧缓存值

问题根因

你当前配置无法在刷新失败时返回旧值,核心原因有3点:

  • refreshAfterWrite触发自动刷新时,会调用CacheLoader.reload(key, oldValue)方法,该方法的默认实现是直接丢弃旧值、调用load(key)拉取新值;如果接口调用失败、返回null或抛出异常,旧值会被直接覆盖/清除,不会自动保留。
  • 你实现的CustomCacheLoader中load方法直接返回null,reload方法完全沿用默认逻辑,没有做异常捕获和旧值回退处理。
  • 构造CaffeineCache时第三个入参allowNullValues设为false,刷新过程中如果产生null值,会直接判定缓存失效,旧值会被立即清除。
修正实现

1. 重写CacheLoader逻辑

核心是在reload方法中捕获所有接口调用异常,刷新失败时直接返回传入的旧值;load方法为首次缓存不存在时的加载逻辑,无旧值可回退,调用失败直接抛出异常即可。

import com.github.benmanes.caffeine.cache.CacheLoader;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

// 替换成你实际的缓存key、value泛型类型,不要用Object
public class CustomCacheLoader implements CacheLoader<String, BankRegistryInfo> {

    // 你的REST调用客户端,根据项目实际情况注入
    private final PbdBankClient pbdBankClient;

    public CustomCacheLoader(PbdBankClient pbdBankClient) {
        this.pbdBankClient = pbdBankClient;
    }

    // 首次缓存不存在时执行加载,无旧值,失败直接抛异常
    @Override
    public @Nullable BankRegistryInfo load(String key) throws Exception {
        return pbdBankClient.queryBankRegistry(key);
    }

    // refreshAfterWrite触发刷新时执行,携带旧值参数
    @Override
    public @Nullable BankRegistryInfo reload(String key, BankRegistryInfo oldValue) throws Exception {
        try {
            BankRegistryInfo newValue = pbdBankClient.queryBankRegistry(key);
            // 接口返回空值也视为刷新失败,回退旧值
            if (newValue == null) {
                return oldValue;
            }
            return newValue;
        } catch (Exception e) {
            // 所有接口调用异常(超时、5xx错误、网络错误等)全部捕获,直接返回旧值
            // 可自行添加错误日志打印,方便排查刷新失败原因
            return oldValue;
        }
    }

    // 以下方法保持默认实现即可,无需修改
    @Override
    public Map<? extends String, ? extends BankRegistryInfo> loadAll(Set<? extends String> keys) throws Exception {
        return CacheLoader.super.loadAll(keys);
    }

    @Override
    public CompletableFuture<? extends BankRegistryInfo> asyncLoad(String key, Executor executor) throws Exception {
        return CacheLoader.super.asyncLoad(key, executor);
    }

    @Override
    public CompletableFuture<? extends Map<? extends String, ? extends BankRegistryInfo>> asyncLoadAll(Set<? extends String> keys, Executor executor) throws Exception {
        return CacheLoader.super.asyncLoadAll(keys, executor);
    }

    @Override
    public CompletableFuture<? extends BankRegistryInfo> asyncReload(String key, BankRegistryInfo oldValue, Executor executor) throws Exception {
        return CacheLoader.super.asyncReload(key, oldValue, executor);
    }
}

2. 调整Caffeine缓存配置

修改CaffeineCache构造参数,正确传入初始化后的CacheLoader,同时开启null值允许,避免极端场景下旧值被意外清除:

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.Cache;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.context.annotation.Bean;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

@Bean
public Collection<? extends Cache> caffeineCaches(PbdBankClient pbdBankClient){
    Collection<CaffeineCache> caffeineCaches = new ArrayList<>();
    caffeineCaches.add(new CaffeineCache("pbdBankRegistry",
            Caffeine.newBuilder()
                    .refreshAfterWrite(2, TimeUnit.MINUTES)
                    .initialCapacity(1)
                    .maximumSize(2)
                    .recordStats()
                    // 传入注入了REST客户端的CacheLoader实例
                    .build(new CustomCacheLoader(pbdBankClient)),
            // 允许null值,避免刷新异常时旧值被意外清除
            true));
    return caffeineCaches;
}

你原有的SimpleCacheManagerXML配置不需要修改,保持原样即可。

注意事项
  • refreshAfterWrite的刷新逻辑是异步执行的:到达刷新周期后,第一个访问缓存的请求会直接返回旧值,后台异步执行刷新任务;刷新成功后后续请求会拿到新值,刷新失败则一直保留旧值直到下一个刷新周期,不会阻塞正常请求。
  • 不要在reload方法中向外抛出异常:如果抛出异常,Caffeine会标记本次刷新失败,下次访问时会触发同步加载,阻塞当前请求,甚至可能清除旧值,所有异常必须在reload方法内部捕获处理。
  • 你使用的Spring版本为4.3.3.RELEASE,Caffeine依赖请选择2.9.x版本,不要使用3.x及以上版本,3.x版本要求JDK11+,且和Spring4内置的CaffeineCache适配器不兼容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:54:25