本文目录导读:

针对Java跨缓存调用的流程统一,核心目标是屏蔽底层缓存差异(Redis、Caffeine、Memcached等),提供一致的编程接口,并灵活处理多级缓存调用链。
以下是实现这一目标的标准化方案,涵盖了架构设计、统一抽象、多级缓存策略及最佳实践:
核心思想:面向接口 + 模板方法 + 多级路由
统一缓存抽象层
定义一个顶级接口,规范所有缓存操作,使业务代码不依赖具体缓存实现。
public interface UnifiedCache {
// 核心操作
<T> T get(String key, Class<T> type);
<T> T get(String key, TypeReference<T> typeRef); // 支持泛型
void set(String key, Object value, long ttl, TimeUnit unit);
void delete(String key);
boolean exists(String key);
// 批量操作
<T> Map<String, T> getMulti(Collection<String> keys, Class<T> type);
void setMulti(Map<String, Object> keyValues, long ttl, TimeUnit unit);
}
多级缓存实现(L1 + L2 架构)
典型架构:本地缓存 (Caffeine) → 分布式缓存 (Redis),实现 UnifiedCache 接口,组合多个缓存层。
public class MultiLevelCache implements UnifiedCache {
private final LocalCache localCache; // Caffeine
private final DistributedCache distCache; // Redis
public MultiLevelCache(LocalCache localCache, DistributedCache distCache) {
this.localCache = localCache;
this.distCache = distCache;
}
@Override
public <T> T get(String key, Class<T> type) {
// 1. 尝试本地缓存
T value = localCache.get(key, type);
if (value != null) {
return value;
}
// 2. 尝试分布式缓存
value = distCache.get(key, type);
if (value != null) {
// 回填本地缓存(可根据情况设置较短TTL)
localCache.set(key, value, 60, TimeUnit.SECONDS);
return value;
}
return null;
}
@Override
public void set(String key, Object value, long ttl, TimeUnit unit) {
// 通常写策略:同时更新两级缓存(或延迟双删)
distCache.set(key, value, ttl, unit);
localCache.set(key, value, localTtlCalc(unit, ttl)); // 本地缓存TTL通常较短
}
@Override
public void delete(String key) {
// 删除策略:先删分布式,再删本地(避免并发读取时的不一致)
distCache.delete(key);
localCache.delete(key);
}
}
// 使用时依赖注入 MultiLevelCache 即可
跨缓存调用流程的统一调度器
对于复杂的缓存调用链(如:查多个缓存源、聚合结果、异常降级),使用管道/过滤器模式或责任链模式管理流程。
public interface CacheInvocationStep {
<T> CacheResult<T> execute(CacheContext context);
}
// 流程编排示例
public class CacheInvocationPipeline {
private List<CacheInvocationStep> steps;
public CacheInvocationPipeline(List<CacheInvocationStep> steps) {
this.steps = steps;
}
public <T> CacheResult<T> execute(String key, Class<T> type) {
CacheContext ctx = new CacheContext(key, type);
for (CacheInvocationStep step : steps) {
CacheResult<T> result = step.execute(ctx);
if (result.success()) {
return result; // 命中则返回
}
// 未命中,传递给下一个步骤,结果可回填。
}
return CacheResult.miss(); // 全未命中,返回空
}
}
// 典型步骤:Caffeine -> Redis -> Database -> 回填缓存
统一监控与降级
包装所有缓存调用,自动采集指标(命中率、耗时、异常),并支持动态降级。
public class MonitoredCache implements UnifiedCache {
private final UnifiedCache delegate;
private final MetricsCollector metrics;
public <T> T get(String key, Class<T> type) {
// 记录耗时、成功/失败、是否命中
metrics.incrementCounter("cache.get.total");
long start = System.nanoTime();
try {
T value = delegate.get(key, type);
if (value != null) {
metrics.incrementCounter("cache.get.hit");
} else {
metrics.incrementCounter("cache.get.miss");
}
return value;
} catch (Exception e) {
metrics.incrementCounter("cache.get.failure");
// 可选降级:是否忽略异常返回null,或抛自定义异常
return null; // 降级处理
} finally {
metrics.recordLatency("cache.get.latency", System.nanoTime() - start);
}
}
}
最佳实践与配置
关键配置项(集中管理,支持动态刷新):
# application.yml (示例)
unified.cache:
layers:
- type: caffeine
max-size: 1000
expire-after-write: 60s
enabled: true
- type: redis
expire-after-write: 3600s
enabled: true
- type: redis-cluster # 可扩展更多缓存层
enabled: false
invocation:
order: caffeine, redis # 调用顺序
fail-fast: false # 是否因某一层失败而中断流程
rollback-to-next: true # 某层失败后是否继续下一层
数据一致性策略(重要):
- 强一致性要求:优先使用先更新数据库,再删除缓存(延迟双删),统一采用
delete而非update(能容忍短暂不一致)。 - 最终一致性:接受短暂差异,使用
set同时更新所有缓存层,并设置合理的TTL。 - 跨地域同步:引入消息队列(如 Canal + MQ)监听数据库变更,广播清除缓存。
完整示例:业务层使用
@Service
public class UserService {
@Autowired
private UnifiedCache unifiedCache; // 注入统一缓存接口
public User getUser(String userId) {
// 调用统一接口,内部自动处理本地->远程->数据库->回填
return unifiedCache.get("user:" + userId, User.class)
.orElseGet(() -> loadFromDbAndCache(userId));
}
public void updateUser(User user) {
// 先更新数据库
userRepository.update(user);
// 统一删除缓存(跨层自动处理)
unifiedCache.delete("user:" + user.getId());
}
}
Java跨缓存调用流程统一的精髓在于:
- 抽象隔离:通过
UnifiedCache接口屏蔽实现细节。 - 层次组合:用
MultiLevelCache实现本地+分布式缓存协同。 - 流程编排:用
Pipeline模式管理调用顺序和降级。 - 非功能关注:统一监控、动态配置、一致性处理。
这样的设计下,业务代码几乎不需要修改即可切换底层缓存中间件,也无需关心多级缓存调用的复杂度。