经典分层
典型后端分层:接口层(Controller)→ 应用/服务层(Service)→ 领域层(Domain)→ 基础设施层(Repository/DB)。每层只依赖下一层抽象。
Controller 管请求响应,Service 管业务规则,Repository 管数据存取。不要把 SQL 写进 Controller,也不要在 Service 里直接拼 HTTP。
依赖方向
依赖应指向稳定抽象(领域),而非易变细节(具体 DB 驱动)。这就是依赖倒置:高层定义接口,低层实现它。
Controller → Service(接口) ← RepositoryImpl
↑ 依赖倒置:Service 不依赖具体存储DDD 入门
领域驱动设计把业务复杂性显式建模:实体(有身份)、值对象(无身份、不可变)、领域服务(跨实体行为)、领域事件。
// 值对象:不可变、按属性相等
public record Money(BigDecimal amount, Currency currency) {
public Money add(Money o) { /* 校验同币种后相加 */ }
}别把所有逻辑塞进 Service 形成"贫血实体"。把业务行为放进领域对象,Service 协调,模型才有生命力。
聚合与仓储
聚合是一致性边界:一个聚合根(如 Order)保证内部不变量,外部只通过根访问。仓储按聚合根而非表组织。
public class Order { // 聚合根
private List<OrderItem> items;
public void addItem(Product p, int qty) {
if (qty <= 0) throw new IllegalArgumentException();
items.add(new OrderItem(p, qty));
}
}常用设计模式
策略模式(多算法可替换)、模板方法(固定骨架留钩子)、工厂(封装创建)、观察者(领域事件解耦)在后端高频出现。
interface DiscountStrategy { BigDecimal apply(BigDecimal p); }
// 满减 / 折扣 / 会员价 各自实现,运行时选择微服务拆分
按业务边界(限界上下文)拆服务,每服务独立数据库、独立部署。拆得太细则运维复杂,太粗则耦合。
| 维度 | 单体 | 微服务 |
|---|---|---|
| 部署 | 一次发布 | 各自独立 |
| 数据 | 共享库 | 每服务私有库 |
| 团队 | 一个团队 | 多团队自治 |
分布式事务
跨服务无法用本地事务,常用 Saga(补偿式长事务)、TCC、或最终一致(消息队列 + 幂等)。优先"少跨库、靠事件"。
下单: 创建订单(本地) → 发事件 → 库存服务消费扣减
失败: 发"取消"事件 → 各服务补偿回滚2PC 锁资源久、可用性差,多数场景用最终一致 + 幂等消费更稳。
常见陷阱与 FAQ
团队规模与部署频率到瓶颈才考虑。早期单体 + 清晰分层足够,过早拆分会带来分布式复杂度债务。
逻辑散在 Service,实体退化成"数据袋子",复用与一致性难保证,需求变更时易出 bug。把不变量收进领域对象。
多数业务可接受最终一致。用幂等 + 重试 + 补偿即可,强一致成本极高且脆弱。