DDD 领域驱动设计分层架构
DDD(Domain-Driven Design,领域驱动设计)是应对复杂业务系统的架构方法论,由 Eric Evans 在 2003 年提出。其核心思想是:软件模型应该反映业务领域,而不是技术实现。DDD 将系统分为四层,每层只依赖下层:
┌────────────────────────────────────────────────────────────────┐
│ DDD 分层架构 │
├────────────────────────────────────────────────────────────────┤
│ Interface Layer(接口层) │
│ └── Controller / GraphQL Resolver / Event Handler │
│ 职责:接收外部请求,参数验证,转换 DTO │
├────────────────────────────────────────────────────────────────┤
│ Application Layer(应用层) │
│ └── ApplicationService / CommandHandler / QueryHandler │
│ 职责:编排领域服务,管理事务,发布领域事件 │
├────────────────────────────────────────────────────────────────┤
│ Domain Layer(领域层)⭐ 核心 │
│ └── Entity / AggregateRoot / ValueObject / DomainService │
│ └── Repository(接口)/ DomainEvent │
│ 职责:核心业务规则,与技术无关,可独立测试 │
├────────────────────────────────────────────────────────────────┤
│ Infrastructure Layer(基础设施层) │
│ └── RepositoryImpl / JPA Entity / Redis / RabbitMQ │
│ 职责:技术实现,持久化,外部系统集成 │
└────────────────────────────────────────────────────────────────┘
核心概念名词解释
聚合根(Aggregate Root)
聚合是一组相关对象的边界,聚合根是聚合的入口。外部只能通过聚合根访问聚合内的对象,这保证了业务规则和数据一致性的边界。Order 就是一个聚合根,OrderItem 只能通过 Order 访问。
值对象(Value Object)
没有唯一标识、通过属性值来判断相等性的对象,且不可变。如 Money(100, "CNY")、Address("上海市浦东新区")。值对象可以安全地共享和复制,修改时需创建新实例。
领域事件(Domain Event)
表示领域中发生的有业务意义的事情,如 OrderCreatedEvent、OrderPaidEvent。领域事件是解耦聚合间通信的关键机制,也是实现最终一致性的基础。
CQRS(命令查询责任分离)
Command Query Responsibility Segregation,将写操作(Command)和读操作(Query)分离到不同的模型。写模型保证业务规则,读模型专注性能优化(如宽表、物化视图)。
Seata AT 模式
阿里巴巴开源的分布式事务框架 Seata 的自动模式(Auto Transaction)。通过代理数据源,自动记录业务 SQL 的前镜像和后镜像,在事务失败时自动生成反向 SQL 进行回滚,对业务代码侵入最小。
最终一致性(Eventual Consistency)
分布式系统中,允许短暂的数据不一致,但最终所有节点会达到一致状态。相比强一致性(同步等待所有节点确认),最终一致性有更好的可用性和性能,是大多数互联网业务可以接受的。
系统模块划分
电商订单系统
│
├── product-service(商品服务)
│ ├── 商品 CRUD、分类管理
│ └── 商品详情查询(高缓存)
│
├── inventory-service(库存服务)
│ ├── 库存查询
│ ├── 扣减库存(防超卖)
│ └── 库存回滚
│
├── order-service(订单服务)⭐ 核心
│ ├── 创建订单(协调商品/库存/支付)
│ ├── 订单状态机
│ ├── 订单查询(CQRS 读模型)
│ └── 分布式事务管理
│
└── payment-service(支付服务)
├── 发起支付
├── 支付回调处理
└── 退款处理
订单实体与状态机
订单状态机
┌─────────────────────────────────────────────────┐
│ │
│ [PENDING] ──支付成功──→ [PAID] ──发货──→ [SHIPPED]
│ │ │ │
│ 超时取消 支付超时 确认收货
│ │ │ │
│ ▼ ▼ ▼
│ [CANCELLED] [CANCELLED] [COMPLETED]
│ │
│ 任意状态────────────────申请退款──→ [REFUNDING]
│ │
│ 退款成功
│ │
│ ▼
│ [REFUNDED]
└─────────────────────────────────────────────────┘
Order 聚合根实现
@Entity
@Table(name = "orders")
public class Order { // 聚合根
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String orderNo; // 业务订单号(雪花算法生成)
private Long userId;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@Embedded
private Money totalAmount; // 值对象
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
@Transient
private List<DomainEvent> domainEvents = new ArrayList<>();
// 工厂方法:创建订单(保证不变量)
public static Order create(Long userId, List<OrderItem> items) {
Order order = new Order();
order.userId = userId;
order.orderNo = SnowflakeIdGenerator.next();
order.status = OrderStatus.PENDING;
order.items = items;
order.totalAmount = calculateTotal(items);
// 发布领域事件
order.domainEvents.add(new OrderCreatedEvent(order.orderNo, userId));
return order;
}
// 支付成功(状态转换由聚合根控制)
public void markPaid(String paymentId) {
if (this.status != OrderStatus.PENDING) {
throw new BusinessException("只有待支付订单才能标记为已支付");
}
this.status = OrderStatus.PAID;
this.domainEvents.add(new OrderPaidEvent(this.orderNo, paymentId));
}
public void cancel(String reason) {
if (!OrderStatus.CANCELLABLE_STATUSES.contains(this.status)) {
throw new BusinessException("当前状态不可取消");
}
this.status = OrderStatus.CANCELLED;
this.domainEvents.add(new OrderCancelledEvent(this.orderNo, reason));
}
}
下单完整链路与分布式事务
用户发起下单请求
│
▼
OrderApplicationService.createOrder()
│
├── @GlobalTransactional ← Seata 开启全局事务(XID)
│
├── 1. 查询商品信息(productClient.getProducts)
│
├── 2. 创建订单(Order.create())→ 保存到 DB
│ └── 本地事务 BEGIN
│ INSERT INTO orders ...
│ INSERT INTO order_items ...
│ 本地事务 COMMIT
│ └── Seata 记录 undo_log(后镜像)
│
├── 3. 扣减库存(inventoryClient.decreaseStock)
│ └── 库存服务本地事务
│ UPDATE inventory SET stock = stock - N WHERE product_id = ?
│ Seata 记录 undo_log
│
├── 4. 发起支付(paymentClient.createPayment)
│ └── 支付服务本地事务
│
├── ✅ 全部成功 → Seata TC 通知各服务提交(二阶段 COMMIT)
│ 删除所有 undo_log
│
└── ❌ 某步失败 → Seata TC 通知各服务回滚(二阶段 ROLLBACK)
各服务用 undo_log 生成反向 SQL 恢复数据
ApplicationService 实现
@Service
@RequiredArgsConstructor
public class OrderApplicationService {
private final OrderRepository orderRepository;
private final ProductClient productClient;
private final InventoryClient inventoryClient;
private final PaymentClient paymentClient;
private final ApplicationEventPublisher eventPublisher;
@GlobalTransactional // Seata 全局事务
public OrderDTO createOrder(CreateOrderCommand cmd) {
// 1. 查询并验证商品
List<ProductDTO> products = productClient.getProducts(cmd.getProductIds());
validateProducts(products, cmd);
// 2. 构建订单项
List<OrderItem> items = buildOrderItems(products, cmd);
// 3. 创建订单聚合根
Order order = Order.create(cmd.getUserId(), items);
orderRepository.save(order);
// 4. 扣减库存(Seata 管理跨服务事务)
inventoryClient.decreaseStock(
items.stream().map(StockDecreaseItem::from).toList()
);
// 5. 创建支付单
String paymentUrl = paymentClient.createPayment(
order.getOrderNo(), order.getTotalAmount()
);
// 6. 发布领域事件(Seata 提交后才发布,避免事件先于数据)
order.getDomainEvents().forEach(eventPublisher::publishEvent);
return OrderDTO.from(order, paymentUrl);
}
}
领域事件监听与最终一致性
@Component
@RequiredArgsConstructor
public class OrderEventHandler {
private final RabbitTemplate rabbitTemplate;
private final EmailService emailService;
private final PointsService pointsService;
// 订单创建后:发送确认邮件(异步,不影响主流程)
@EventListener
@Async
public void onOrderCreated(OrderCreatedEvent event) {
emailService.sendOrderConfirmation(event.getUserId(), event.getOrderNo());
}
// 订单支付后:通过 RabbitMQ 通知仓储系统发货
@EventListener
public void onOrderPaid(OrderPaidEvent event) {
rabbitTemplate.convertAndSend(
"order.events", "order.paid",
new ShipmentCreationCommand(event.getOrderNo())
);
// 异步增加积分(最终一致性)
pointsService.addPointsAsync(event.getUserId(), event.getAmount());
}
}
项目完整目录结构
order-service/
├── src/main/java/com/ecommerce/order/
│ │
│ ├── interfaces/ # 接口层
│ │ ├── rest/
│ │ │ └── OrderController.java
│ │ ├── dto/
│ │ │ ├── CreateOrderRequest.java
│ │ │ └── OrderResponse.java
│ │ └── event/
│ │ └── PaymentCallbackHandler.java
│ │
│ ├── application/ # 应用层
│ │ ├── service/
│ │ │ └── OrderApplicationService.java
│ │ ├── command/
│ │ │ └── CreateOrderCommand.java
│ │ └── event/
│ │ └── OrderEventHandler.java
│ │
│ ├── domain/ # 领域层(核心,无技术依赖)
│ │ ├── model/
│ │ │ ├── Order.java # 聚合根
│ │ │ ├── OrderItem.java
│ │ │ ├── OrderStatus.java # 枚举 + 状态机规则
│ │ │ └── Money.java # 值对象
│ │ ├── repository/
│ │ │ └── OrderRepository.java # 接口(依赖倒置)
│ │ ├── service/
│ │ │ └── OrderDomainService.java
│ │ └── event/
│ │ ├── OrderCreatedEvent.java
│ │ └── OrderPaidEvent.java
│ │
│ └── infrastructure/ # 基础设施层
│ ├── persistence/
│ │ └── JpaOrderRepository.java # Repository 实现
│ ├── client/
│ │ ├── ProductClient.java # Feign 客户端
│ │ └── InventoryClient.java
│ └── config/
│ ├── SeataConfig.java
│ └── RabbitConfig.java
│
└── src/main/resources/
├── application.yml
└── application-prod.yml
Tip
优先考虑业务可接受的最终一致性,而非强一致性。大多数电商场景(积分、通知、统计)都可以接受秒级到分钟级的最终一致,不必引入 Seata 等复杂的分布式事务。只有核心的金融操作(扣款+出库同时成功或同时失败)才需要强一致性保证。
Info
至此,你已掌握了 Java Spring Boot 服务端开发的完整技术栈:从 IoC/DI 基础原理,到 REST API 设计、JPA 数据访问、Security 认证授权、缓存、消息队列、微服务,直到容器化部署和 DDD 实战架构。这些技能足以支撑你构建企业级生产应用。
课程总结
- Chapter 1–2:Spring 核心思想与 REST API 设计规范
- Chapter 3–4:数据持久化(JPA)与安全(Security + JWT)
- Chapter 5:测试体系(单元/集成/TestContainers)
- Chapter 6–7:缓存(Redis)与异步通信(RabbitMQ)
- Chapter 8–9:微服务(Spring Cloud)与容器化(Docker/K8s)
- Chapter 10:DDD 实战架构,分布式事务 Seata