第3章:缓存抽象层的整体架构蓝图——分层模型、模块划分与组件依赖
3.1 架构边界与上下文
缓存抽象层位于业务系统与具体缓存中间件之间,其核心使命是将缓存操作与底层实现解耦。本章定义的边界如下:
- 上边界:业务代码通过统一 API 读写缓存,不感知后端是 Redis、Memcached 还是本地堆缓存。
- 下边界:抽象层对接具体缓存客户端(如 Jedis、Redisson、Memcached client),通过适配器模式屏蔽差异。
- 侧边界:与配置中心、监控系统、序列化组件通过 SPI 或依赖注入集成,不直接硬编码。
架构约束: 抽象层内部不允许出现业务逻辑判断,所有缓存策略(TTL、备用、降级)必须在策略层声明,不得渗透到接口层。
3.2 三层分层模型
缓存抽象层采用严格的三层垂直划分,每层各司其职,依赖方向自顶向下:
| 层次 | 核心职责 | 典型模块 | 对外依赖 |
|---|---|---|---|
| 接口层 | 暴露稳定 API 给业务方;定义缓存操作契约 | CacheClient、@Cacheable 注解解析器、批量操作接口 | 不依赖任何下层实现 |
| 策略层 | 管理缓存策略(TTL、淘汰、降级、备份);路由请求到合适的实现 | CachePolicyManager、FallbackRouter、CacheKeyBuilder | 依赖接口层定义的接口 |
| 实现层 | 封装具体缓存中间件;提供连接池、序列化、故障转移 | RedisAdapter、LocalCacheAdapter、CompositeCacheAdapter | 依赖策略层定义的策略配置 |
设计观点: 策略层是分层模型中最关键的“胶水”层——它决定了缓存行为(如热点数据是否自动备份到本地),而实现层只关心如何存取。
3.3 组件依赖关系图
下图展示了缓存抽象层内主要模块的依赖与协作关系。注意箭头方向表示“依赖或调用”:
3.4 数据流与控制流
一次典型的缓存写入请求经过以下路径:
- 接口层接收
set(key, value, ttl),将其包装为CacheWriteRequest上下文对象。 - 策略层的
CachePolicyManager根据 key 的配置决定写入策略(如是否同步写本地+远程、是否压缩)。 - 实现层的
RedisAdapter或LocalCacheAdapter执行真正存储,并返回结果。 - 结果按原路返回,策略层可将结果写入监控指标。
控制流中最重要的信任链路在于:策略层信任接口层传入的 key 合法性(格式校验已在接口层完成),实现层信任策略层下发的配置(如连接超时等)。任何跨层信任违规都应通过契约测试捕获。
3.5 选型权衡
| 决策点 | 方案A | 方案B | 建议场景 |
|---|---|---|---|
| 策略层是否独立为微服务 | 嵌入 SDK | 独立 sidecar | 简单场景用 SDK;多语言或策略热更新用 sidecar |
| 接口层是否提供异步回调 | 仅同步 | CompletableFuture | 高吞吐场景推荐异步 |
| 实现层适配器数量 | 仅 Redis | Redis + Local + 其他 | 混合缓存场景需要 Composite |
3.6 风险点与应对
- 循环依赖:策略层不应反向依赖实现层的具体类,必须通过接口或 SPI 解耦。解决方案是引入
CacheProviderRegistry实现服务发现。 - 过度抽象:三层结构在小型项目可能增加复杂性。应对:允许实现层直接提供简单 API 绕过策略层(需配置开关)。
- 序列化不一致:不同实现层可能要求不同序列化方式。策略层应提供统一的序列化器选择入口。
3.7 落地步骤
- 定义接口层接口契约(不少于 5 个核心方法),并编写测试用例。
- 实现策略层的
CachePolicyManager骨架,初始化时注入默认策略。 - 选择一个实现层适配器(如 RedisAdapter)进行联调。
- 添加配置注入路径(如 yaml 文件读取)。
- 编写跨层集成测试,验证请求流转完整性。
3.8 验收标准
本章架构蓝图通过验收需满足:
- 层间隔离:接口层代码不引入任何实现层 import(通过 SPI 或工厂类)。
- 策略可替换:修改
cache-policy.yml即可切换 TTL 策略,无需改动代码。 - 数据流可观测:在策略层增加一条日志,即能输出完整的调用链路。
- 依赖图一致性:自动化工具(如 Dependency Graph)检查无循环依赖。
实践提示: 验收阶段建议使用
./gradlew dependencies --configuration runtimeClasspath 确认各模块之间无反向依赖。若发现策略层引用了 RedisAdapter,则视为架构违规。