第6章:集成(Integration)
一、导读
1.1 本章学习目标
第6章讲解限界上下文之间的集成方式。
本章的核心学习目标包括:
- 掌握上下文映射的实现模式
- 理解防腐层的设计
- 学会使用领域事件进行集成
- 理解 CQRS 和事件溯源
1.2 为什么本章如此重要
系统不是孤立的——上下文之间需要协作。错误的集成方式会导致上下文之间的耦合,破坏限界边界的隔离。
1.3 核心问题引导
防腐层如何保护内部模型?
领域事件如何实现松耦合集成?
CQRS 解决了什么问题?
事件溯源有什么优缺点?
二、核心概念详解
2.1 防腐层
java
// 防腐层:隔离外部系统的模型
public class ExternalPaymentGateway implements PaymentGateway {
private StripeClient stripe; // 外部 SDK
@Override
public PaymentResult processPayment(PaymentCommand cmd) {
// 将内部模型转换为外部模型
StripeChargeRequest request = new StripeChargeRequest();
request.setAmount(cmd.getAmount().getAmount().intValue());
request.setCurrency(cmd.getAmount().getCurrency().getCode());
request.setSource(cmd.getToken());
// 调用外部服务
StripeChargeResponse response = stripe.charge(request);
// 将外部模型转换回内部模型
return new PaymentResult(
response.getId(),
PaymentStatus.fromStripe(response.getStatus()),
response.getReceiptUrl()
);
}
}2.2 领域事件集成
java
// 发布事件
public class OrderApplicationService {
private EventPublisher eventPublisher;
public void confirmOrder(ConfirmOrderCommand cmd) {
Order order = orderRepository.findById(cmd.getOrderId());
order.confirm();
orderRepository.save(order);
// 发布领域事件
for (DomainEvent event : order.getEvents()) {
eventPublisher.publish(event);
}
}
}
// 消费事件
public class InventoryEventHandler {
@EventListener
public void onOrderConfirmed(OrderConfirmed event) {
// 更新库存
for (OrderLineItem item : event.getItems()) {
inventoryService.reduceStock(item.getProductId(), item.getQuantity());
}
}
}2.3 CQRS
java
// 命令端:修改状态
public class OrderCommandHandler {
public void placeOrder(PlaceOrderCommand cmd) {
Order order = new Order(cmd.getCustomerId());
// ... 业务逻辑
orderRepository.save(order);
eventPublisher.publish(new OrderPlaced(order.getId()));
}
}
// 查询端:读取数据(使用专门的读模型)
public class OrderQueryService {
private JdbcTemplate jdbc; // 直接用 SQL 查询
public List<OrderView> findOrders(OrderQuery query) {
String sql = "SELECT o.id, o.total, c.name FROM orders o " +
"JOIN customers c ON o.customer_id = c.id " +
"WHERE o.status = ?";
return jdbc.query(sql, new Object[]{query.getStatus()},
(rs, n) -> new OrderView(rs.getString("id"), rs.getBigDecimal("total")));
}
}三、实战案例
3.1 案例一:事件溯源
java
// 事件溯源:用事件序列表示状态
public class Order {
private OrderId id;
private List<OrderLine> lines = new ArrayList<>();
private OrderStatus status = OrderStatus.DRAFT;
private List<DomainEvent> changes = new ArrayList<>();
// 应用事件
public void apply(DomainEvent event) {
if (event instanceof OrderLineAdded) {
OrderLineAdded e = (OrderLineAdded) event;
lines.add(new OrderLine(e.getProductId(), e.getQuantity()));
} else if (event instanceof OrderConfirmed) {
status = OrderStatus.CONFIRMED;
}
changes.add(event);
}
// 执行业务操作
public void addLine(ProductId productId, int quantity) {
apply(new OrderLineAdded(id, productId, quantity));
}
// 从事件重建状态
public static Order rehydrate(OrderId id, List<DomainEvent> events) {
Order order = new Order();
order.id = id;
events.forEach(order::apply);
return order;
}
}四、本章小结
防腐层:隔离外部系统模型。
领域事件:松耦合的上下文集成。
CQRS:命令和查询分离,优化读写性能。
事件溯源:用事件序列表示状态。
五、思考与练习
设计一个防腐层来隔离第三方支付网关。
用领域事件实现订单和库存上下文的集成。
CQRS 在什么场景下最有价值?