如何为Guava Cache不同Key设置独立refreshAfterWrite时间?
单CacheLoader实现多Key独立刷新方案
完全可以通过单个CacheLoader实现你的需求,核心是用带类型标识的缓存Key区分两个集合,结合定时任务触发不同Key的异步刷新,同时保证单次API调用即可更新两个缓存项。以下是具体实现:
1. 定义区分类型的缓存Key
先创建枚举标识两种交易集合,再封装成缓存Key:
enum TransactionCacheType { ALLOWED, DENIED } record TransactionCacheKey(TransactionCacheType type) {}
2. 实现单CacheLoader加载完整数据
CacheLoader的load方法只调用一次API获取完整的Transactions对象,同时更新两个缓存项;reload方法复用加载逻辑,保证异步刷新时也是单次API调用:
public class TransactionsDetailsCacheLoader extends CacheLoader<TransactionCacheKey, Set<String>> { private final LoadingCache<TransactionCacheKey, Set<String>> cache; private final TransactionApiClient apiClient; // 构造函数注入缓存实例和API客户端 public TransactionsDetailsCacheLoader(LoadingCache<TransactionCacheKey, Set<String>> cache, TransactionApiClient apiClient) { this.cache = cache; this.apiClient = apiClient; } @Override public Set<String> load(TransactionCacheKey key) throws Exception { // 单次API调用拉取完整数据 Transactions transactions = apiClient.fetchAllTransactions(); // 同时更新两个缓存项,保证数据一致性 cache.put(new TransactionCacheKey(TransactionCacheType.ALLOWED), transactions.getAllowedTransactions()); cache.put(new TransactionCacheKey(TransactionCacheType.DENIED), transactions.getDeniedTransactions()); // 返回当前请求Key对应的集合 return switch (key.type()) { case ALLOWED -> transactions.getAllowedTransactions(); case DENIED -> transactions.getDeniedTransactions(); }; } @Override public ListenableFuture<Set<String>> reload(TransactionCacheKey key, Set<String> oldValue) { // 复用load逻辑,异步刷新时同样单次API调用更新两个缓存 return Futures.immediateFuture(load(key)); } }
3. 初始化缓存与定时刷新任务
不设置全局refreshAfterWrite,而是通过定时任务分别控制两个Key的异步刷新间隔,同时配置兜底过期时间防止任务异常:
// 初始化缓存:设置兜底过期时间(比刷新间隔略长即可) LoadingCache<TransactionCacheKey, Set<String>> transactionCache = CacheBuilder.newBuilder() .expireAfterWrite(1, TimeUnit.HOURS) // 兜底:1小时未刷新则过期 .build(new TransactionsDetailsCacheLoader(transactionCache, apiClient)); // 初始化定时任务池 ScheduledExecutorService refreshScheduler = Executors.newSingleThreadScheduledExecutor(); // 配置ALLOWED Key的刷新:每1小时一次 refreshScheduler.scheduleAtFixedRate( () -> transactionCache.refresh(new TransactionCacheKey(TransactionCacheType.ALLOWED)), 0, // 首次立即执行 1, TimeUnit.HOURS ); // 配置DENIED Key的刷新:每5分钟一次 refreshScheduler.scheduleAtFixedRate( () -> transactionCache.refresh(new TransactionCacheKey(TransactionCacheType.DENIED)), 0, 5, TimeUnit.MINUTES );
4. 缓存使用方式
通过对应Key直接获取目标集合:
// 获取允许的交易集合 Set<String> allowedTransactions = transactionCache.get(new TransactionCacheKey(TransactionCacheType.ALLOWED)); // 获取拒绝的交易集合 Set<String> deniedTransactions = transactionCache.get(new TransactionCacheKey(TransactionCacheType.DENIED));
核心优势
- 单CacheLoader实现,无需拆分缓存,保证API调用只触发一次
- 两个Key独立配置刷新间隔,满足1小时和5分钟的需求
- 异步刷新不阻塞业务请求,同时兜底过期时间避免缓存失效
内容的提问来源于stack exchange,提问作者Logic
相关产品推荐
相关产品推荐

