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

清洁架构中缓存位置选择:微服务缓存实现方案咨询

缓存逻辑的合理分层实现方案

两种方案的优劣与适用场景

方案1:服务层处理缓存缺失(不推荐)

这种方式会让服务层承担原本属于数据访问层的职责,破坏单一职责原则。服务层应聚焦业务逻辑,而非数据缓存、读取的细节。后续若要移除缓存,必须修改服务层代码,违反开闭原则,还会让服务层与具体仓储实现耦合,失去接口解耦的意义。

方案2:仓储层处理缓存缺失(可优化)

这个思路的核心是正确的——仓储层的职责就是封装数据获取细节,不管数据来自缓存还是数据库,服务层只需调用CustomerRepository接口即可。你担心的循环依赖问题,可通过装饰器模式解决:

  • 让CacheCustomerRepositoryImpl依赖CustomerRepository接口(而非具体的DbCustomerRepositoryImpl)
  • 缓存缺失时,调用注入的CustomerRepository实例(即DbCustomerRepositoryImpl)获取数据,写入缓存后返回
  • 这种方式下,CacheCustomerRepositoryImpl是对底层仓储的增强,而非独立实现,完全避免循环依赖

示例代码结构:

public class CacheCustomerRepositoryImpl implements CustomerRepository {
    private final CustomerRepository delegate;
    private final Cache cache;

    // 构造注入依赖的仓储实现
    public CacheCustomerRepositoryImpl(CustomerRepository delegate, Cache cache) {
        this.delegate = delegate;
        this.cache = cache;
    }

    @Override
    public Customer findById(int id) {
        Customer customer = cache.get(id);
        if (customer == null) {
            customer = delegate.findById(id);
            if (customer != null) {
                cache.put(id, customer);
            }
        }
        return customer;
    }
}

缓存业务逻辑返回结果的处理方式

如果需要缓存的是业务逻辑的计算结果(而非单纯仓储数据),缓存逻辑就不属于仓储层了,推荐两种方式:

  • AOP切面实现:在服务层方法上添加自定义缓存注解,通过切面统一处理缓存的读取、写入和失效。这种方式完全不侵入业务代码,符合清洁架构“业务逻辑与基础设施解耦”的原则。
  • 独立缓存服务:创建专门的CustomerCacheService封装业务结果的缓存逻辑,服务层按需调用该缓存服务,再根据缓存结果决定是否执行业务逻辑。注意避免缓存服务与业务服务产生耦合。

清洁架构下的最优实践

清洁架构中,缓存属于基础设施层(最外层),需遵循以下原则:

  • 业务层(服务层)完全不感知缓存存在,仅依赖抽象的仓储接口
  • 缓存逻辑通过装饰器或切面封装在基础设施层,作为对仓储或服务的增强
  • 所有依赖方向为内层(业务层)依赖外层(基础设施层),避免反向依赖

这样既保证各层职责清晰,又能灵活添加、移除缓存逻辑,无需修改核心业务代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 11:03:35