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

Spring缓存实现:定时任务仅写缓存,其他请求优先读缓存

实现Spring定时任务与普通调用的缓存差异化处理方案

嘿,这个需求在Spring生态里其实很好解决,核心就是要给getData()的两种调用场景做区分——定时任务只负责「刷缓存」,普通调用则「优先读缓存」。我给你整理了几个实用的方案,都是日常开发里常用的:

方案一:拆分方法+Spring Cache注解(最推荐)

这是最符合单一职责原则的做法,把原来的getData()拆成两个方法,分别对应读缓存+回源和直接查源+写缓存的逻辑:

@Service
public class DataService {

    // 普通消费者调用这个:优先读缓存,缓存空才去查源数据
    @Cacheable(value = "dataCache", key = "#requestKey")
    public Data getData(String requestKey) {
        return fetchDataFromSource(requestKey); // 从数据库/第三方接口等源获取数据
    }

    // 定时任务专属方法:直接查源,然后强制写入缓存
    @CachePut(value = "dataCache", key = "#requestKey")
    public Data refreshData(String requestKey) {
        return fetchDataFromSource(requestKey);
    }

    // 实际获取源数据的私有方法,封装核心逻辑
    private Data fetchDataFromSource(String requestKey) {
        // 这里写真正的数据源调用逻辑,比如DB查询、HTTP请求等
        return new Data();
    }
}

然后定时任务里直接调用refreshData()就行:

@Component
public class DataRefreshTask {

    @Autowired
    private DataService dataService;

    @Scheduled(fixedRate = 3600000) // 示例:每小时执行一次
    public void scheduledDataRefresh() {
        String targetRequestKey = "your-specific-key"; // 根据业务传入对应的请求key
        dataService.refreshData(targetRequestKey);
    }
}

这里的关键是:@CachePut不管缓存有没有数据,都会执行方法体然后把结果写入缓存,完美匹配定时任务「只写不读」的需求;而@Cacheable会先检查缓存,不存在才执行方法,刚好满足普通消费者的逻辑。

方案二:重载方法+注解条件(不修改原有调用)

如果不想改动原有消费者的调用代码,可以通过重载方法+注解的条件判断来实现:

@Service
public class DataService {

    // 原有方法,供普通消费者调用(保持兼容)
    @Cacheable(value = "dataCache", key = "#requestKey")
    public Data getData(String requestKey) {
        return fetchDataFromSource(requestKey);
    }

    // 定时任务专用的重载方法,强制更新缓存
    @CachePut(value = "dataCache", key = "#requestKey")
    public Data getData(String requestKey, boolean isScheduledCall) {
        return fetchDataFromSource(requestKey);
    }

    private Data fetchDataFromSource(String requestKey) {
        // 源数据获取逻辑
        return new Data();
    }
}

定时任务调用时传入isScheduledCall=true,此时@CachePut生效直接更新缓存;普通消费者调用无参数的原有方法,@Cacheable正常工作。

方案三:手动操作缓存(灵活度最高)

如果Spring Cache的注解满足不了更复杂的缓存逻辑(比如自定义过期时间、缓存失败降级),可以直接用CacheManager手动控制缓存读写:

@Service
public class DataService {

    @Autowired
    private CacheManager cacheManager;

    // 普通消费者调用:先读缓存,无数据则查源并存缓存
    public Data getData(String requestKey) {
        Cache cache = cacheManager.getCache("dataCache");
        if (cache != null) {
            Data cachedData = cache.get(requestKey, Data.class);
            if (cachedData != null) {
                return cachedData;
            }
        }
        Data freshData = fetchDataFromSource(requestKey);
        if (cache != null) {
            cache.put(requestKey, freshData);
        }
        return freshData;
    }

    // 定时任务调用:直接查源,强制更新缓存
    public void refreshData(String requestKey) {
        Data freshData = fetchDataFromSource(requestKey);
        Cache cache = cacheManager.getCache("dataCache");
        if (cache != null) {
            cache.put(requestKey, freshData);
        }
    }

    private Data fetchDataFromSource(String requestKey) {
        // 源数据获取逻辑
        return new Data();
    }
}

这种方式完全手动控制缓存的每一步操作,适合需要精细管控缓存行为的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:07:47