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
相关产品推荐
相关产品推荐

