对于架构风格/模式选择: 决定系统整体组织形式。常见的有:
分层架构(如 MVC, OSI 模型)
客户端-服务器架构
面向服务架构
微服务架构
事件驱动架构
管道-过滤器架构
发布-订阅架构
领域驱动设计(DDD)的应用
我们选择一种架构风格或模式时,需要根据系统的业务需求、复杂性、团队结构、可扩展性、可维护性等多种因素来综合考虑。下面我将详细讨论每种架构风格/模式的核心思想、适用场景以及实例,并说明如何选择。
-
分层架构(Layered Architecture)
核心思想:将系统划分为若干层次,每个层次负责特定的职责,层次之间通过定义良好的接口进行通信,通常上层依赖下层。
常见分层:表示层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。
优点:关注点分离,易于理解和维护,可以分层测试和替换。
缺点:性能可能略有损失(因为层层调用),不适合高性能系统,过度分层可能导致架构复杂。
实例:MVC模式(Model-View-Controller)是分层架构的一种变体,将应用程序分为模型、视图和控制器三层。 -
客户端-服务器架构(Client-Server)
核心思想:将系统分为客户端和服务器两部分,客户端发送请求,服务器处理请求并返回响应。
优点:分离前后端关注点,服务器可以集中管理数据和业务逻辑,客户端可以多样化(Web、移动、桌面)。
缺点:服务器可能成为瓶颈,且单点故障问题。
实例:传统的Web应用,如电子商务网站,前端浏览器作为客户端,后端服务器处理业务逻辑。 -
面向服务架构(Service-Oriented Architecture, SOA)
核心思想:将系统划分为一组松耦合的服务,服务之间通过标准化的接口(如Web服务)进行通信。
优点:提高系统灵活性,可重用性,易于集成和扩展。
缺点:服务划分和治理复杂,可能引入性能开销。
实例:企业服务总线(ESB)是SOA的一种实现方式,用于集成企业内各种异构系统。 -
微服务架构(Microservices Architecture)
核心思想:是SOA的一种细化,将应用程序构建为一组小型、独立的服务,每个服务运行在自己的进程中,通过轻量级机制(如HTTP/REST)通信。
优点:每个服务可独立开发、部署和扩展,技术栈灵活,容错性好。
缺点:分布式系统复杂性高,数据一致性、测试和监控挑战大。
实例:Netflix、Amazon等大型互联网公司采用微服务架构。 -
事件驱动架构(Event-Driven Architecture, EDA)
核心思想:系统组件通过事件进行通信,事件生产者发布事件,事件消费者订阅事件并作出响应。
优点:松耦合,异步处理,可扩展性好,实时响应。
缺点:事件流复杂,难以调试,可能事件丢失或重复。
实例:金融交易系统、实时监控系统。 -
管道-过滤器架构(Pipe-Filter Architecture)
核心思想:将系统分解为一系列的处理步骤(过滤器),每个步骤通过管道传递数据流。
优点:易于理解和维护,每个过滤器可以独立开发和测试。
缺点:不适合交互式应用,数据传输可能成为瓶颈。
实例:编译器(词法分析、语法分析、语义分析、代码生成)、Unix的shell命令(通过管道连接多个命令)。 -
发布-订阅架构(Publish-Subscribe Architecture)
核心思想:是事件驱动架构的一种,消息的发送者(发布者)将消息分类发布,而不需要知道订阅者是谁。订阅者接收感兴趣的消息,而不需要知道发布者是谁。
优点:高度解耦,可扩展性强。
缺点:消息传递可能不可靠,顺序可能错乱。
实例:消息队列系统(如RabbitMQ、Kafka)常用于实现发布-订阅模式。 -
领域驱动设计(Domain-Driven Design, DDD)
核心思想:通过将复杂业务领域划分为多个子域,并针对每个子域建立领域模型,通过模型驱动设计。
优点:将业务复杂性纳入设计,提高软件对业务的表达能力,适合复杂业务系统。
缺点:学习曲线陡峭,需要领域专家参与。
实例:大型企业业务系统,如银行核心系统、保险系统。
如何选择?
选择架构风格时,可以考虑以下因素:
-
系统复杂性:简单系统可以用分层架构,复杂业务系统可能适合DDD,大型互联网应用可能适合微服务。
-
团队结构:小团队适合单体分层,大团队多个小团队适合微服务。
-
性能要求:高性能、低延迟系统可能需要事件驱动或管道-过滤器。
-
可扩展性:需要水平扩展的考虑微服务、事件驱动。
-
可维护性:分层架构和微服务架构通常更易于维护。
-
技术栈:现有技术栈可能对架构有影响,如Java Spring Cloud适合微服务。
实例:假设我们要设计一个大型电商平台,它需要处理高并发、海量数据,并且业务复杂(包括商品、订单、库存、支付、物流等)。我们可以这样选择:
-
整体采用微服务架构,将系统划分为多个微服务(商品服务、订单服务、库存服务等),每个服务独立开发部署。
-
在微服务内部,采用分层架构(Controller、Service、Repository)。
-
服务之间采用事件驱动架构,通过消息队列(如Kafka)进行异步通信,实现解耦和削峰填谷。
-
在核心的订单和库存服务中,采用DDD进行领域建模,确保业务逻辑的正确性和复杂性管理。
-
前端采用客户端-服务器架构,多种客户端(Web、App)通过API网关访问后端服务。
这样,我们综合运用了多种架构风格,以应对不同的需求和挑战。
概述总结:架构风格的选择不是单一的,通常需要根据实际情况组合多种风格。理解每种风格的核心思想和适用场景,有助于我们做出合理的选择
架构风格/模式选择:系统组织形式决策指南
下面将深入解析每种架构风格的核心机制、适用场景、权衡考量,并通过具体实例展示如何选择和组合这些架构模式。
一、架构选择决策框架
1.1 选择矩阵:基于系统特征
| 特征维度 | 推荐架构 | 理由 |
|---|---|---|
| 简单业务,小团队 | 分层架构/MVC | 简单直接,快速启动 |
| 复杂业务逻辑 | 领域驱动设计(DDD) + 分层 | 确保业务模型与技术实现一致 |
| 高并发,事件密集型 | 事件驱动架构 | 异步处理,解耦生产者与消费者 |
| 需要独立扩展组件 | 微服务架构 | 按需扩展,独立部署 |
| 已有异构系统集成 | 面向服务架构(SOA) | 标准化集成,重用现有服务 |
| 数据处理流水线 | 管道-过滤器架构 | 线性数据处理流程 |
| 实时消息广播 | 发布-订阅架构 | 一对多消息分发 |
| 分布式,跨网络 | 客户端-服务器架构 | 清晰分离关注点 |
1.2 评估维度对比
class ArchitectureEvaluator:
"""架构选择评估模型"""
DIMENSIONS = {
'complexity': ('开发复杂性', 1, 5), # 1=简单,5=复杂
'scalability': ('可扩展性', 1, 5),
'maintainability': ('可维护性', 1, 5),
'performance': ('性能', 1, 5),
'fault_tolerance': ('容错性', 1, 5),
'deployability': ('可部署性', 1, 5),
'team_size': ('所需团队规模', 'small', 'large')
}
def evaluate(self, architecture, requirements):
"""评估架构是否满足需求"""
scores = {}
for dim, (desc, min_val, max_val) in self.DIMENSIONS.items():
score = self._score_dimension(architecture, dim, requirements)
scores[dim] = score
return scores
def _score_dimension(self, architecture, dimension, requirements):
"""具体评分逻辑"""
scoring_rules = {
'monolithic': {
'complexity': 2, # 相对简单
'scalability': 3, # 垂直扩展为主
'deployability': 5, # 一次部署
},
'microservices': {
'complexity': 5, # 分布式复杂性高
'scalability': 5, # 可独立水平扩展
'fault_tolerance': 4, # 故障隔离
'deployability': 3, # 多服务协调部署
},
'event_driven': {
'performance': 4, # 异步高性能
'scalability': 5, # 消费者可独立扩展
'complexity': 4, # 事件溯源复杂
}
}
return scoring_rules.get(architecture, {}).get(dimension, 3)
二、分层架构
2.1 核心机制与原理
机制:垂直分层 + 单向依赖
表示层 (Presentation)
↓
业务逻辑层 (Business Logic)
↓
数据访问层 (Data Access)
↓
基础设施层 (Infrastructure)
原理:
- 关注点分离:每层有明确职责
- 单向依赖:上层依赖下层,下层不知道上层
- 接口抽象:层间通过接口通信,隐藏实现
2.2 实例:电商网站分层架构
// 1. 表示层 - Web控制器
@RestController
@RequestMapping("/orders")
public class OrderController {
@Autowired
private OrderService orderService; // 依赖业务层接口
@PostMapping
public ResponseEntity<OrderDTO> createOrder(@RequestBody CreateOrderRequest request) {
Order order = orderService.createOrder(request);
return ResponseEntity.ok(OrderMapper.toDTO(order));
}
}
// 2. 业务逻辑层 - 服务实现
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderRepository orderRepository; // 依赖数据层接口
@Autowired
private InventoryService inventoryService;
@Autowired
private PaymentService paymentService;
@Override
@Transactional
public Order createOrder(CreateOrderRequest request) {
// 1. 验证库存
inventoryService.checkAvailability(request.getItems());
// 2. 创建订单实体
Order order = new Order(request.getCustomerId(), request.getItems());
// 3. 处理支付
PaymentResult result = paymentService.processPayment(
order.getTotalAmount(),
request.getPaymentMethod()
);
// 4. 保存订单
order.confirm(result.getTransactionId());
return orderRepository.save(order);
}
}
// 3. 数据访问层 - 仓储接口
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByCustomerIdAndStatus(Long customerId, OrderStatus status);
}
// 4. 领域层 - 核心业务对象
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long customerId;
@OneToMany(cascade = CascadeType.ALL)
private List<OrderItem> items;
private BigDecimal totalAmount;
private OrderStatus status;
// 领域行为
public void cancel() {
if (!this.status.canCancel()) {
throw new IllegalStateException("Cannot cancel order in " + this.status);
}
this.status = OrderStatus.CANCELLED;
}
public void addItem(Product product, int quantity) {
OrderItem item = new OrderItem(product, quantity);
this.items.add(item);
recalculateTotal();
}
private void recalculateTotal() {
this.totalAmount = items.stream()
.map(OrderItem::getSubtotal)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
2.3 变体:六边形架构(端口-适配器)
// 端口(领域层定义)
interface OrderRepositoryPort {
Order findById(OrderId id);
void save(Order order);
}
interface PaymentServicePort {
PaymentResult processPayment(PaymentRequest request);
}
// 适配器实现(基础设施层)
@Repository
class OrderRepositoryAdapter implements OrderRepositoryPort {
private final JpaOrderRepository jpaRepository;
@Override
public Order findById(OrderId id) {
OrderEntity entity = jpaRepository.findById(id.getValue())
.orElseThrow(() -> new OrderNotFoundException(id));
return OrderMapper.toDomain(entity);
}
}
@Component
class PaymentServiceAdapter implements PaymentServicePort {
private final ThirdPartyPaymentClient client;
@Override
public PaymentResult processPayment(PaymentRequest request) {
// 适配第三方支付API
ThirdPartyResponse response = client.charge(
request.getOrderId().toString(),
request.getAmount()
);
return PaymentMapper.toDomain(response);
}
}
// 领域层(不依赖外部)
@Service
class OrderService {
private final OrderRepositoryPort orderRepository;
private final PaymentServicePort paymentService;
public Order processOrder(OrderCommand command) {
Order order = Order.create(command);
orderRepository.save(order);
PaymentResult result = paymentService.processPayment(
new PaymentRequest(order.getId(), order.getTotalAmount())
);
order.confirm(result);
orderRepository.save(order);
return order;
}
}
三、微服务架构
3.1 核心机制与原理
机制:服务自治 + 分布式通信
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 服务A │ │ 服务B │ │ 服务C │
│独立进程 │ │独立进程 │ │独立进程 │
│独立部署 │ │独立部署 │ │独立部署 │
│独立数据 │ │独立数据 │ │独立数据 │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└──────────────┴──────────────┘
API网关/服务网格
原理:
- 单一职责:每个服务聚焦一个业务能力
- 独立自治:独立开发、测试、部署、扩展
- 去中心化治理:服务自治,技术栈灵活
- 故障隔离:一个服务故障不影响其他
3.2 实例:电商平台微服务拆分
# 微服务定义与边界
services:
# 核心业务服务
product-service:
职责: "商品管理、分类、搜索"
技术栈: "Java + Spring Boot + Elasticsearch"
数据存储: "MySQL + Redis缓存"
端点:
- GET /api/products/{id}
- GET /api/products/search?q={query}
- POST /api/products
order-service:
职责: "订单创建、状态管理、订单查询"
技术栈: "Go + gRPC"
数据存储: "PostgreSQL"
通信: "gRPC(内部), REST(外部)"
inventory-service:
职责: "库存管理、扣减、预警"
技术栈: "Java + Spring Boot"
数据存储: "MySQL + Redis(库存缓存)"
特性: "分布式锁、乐观锁控制并发"
payment-service:
职责: "支付处理、退款、对账"
技术栈: "Node.js + TypeScript"
数据存储: "MongoDB(交易日志)"
外部集成: ["支付宝", "微信支付", "银联"]
# 支撑服务
user-service:
职责: "用户认证、授权、个人信息"
技术栈: "Python + Django"
数据存储: "PostgreSQL"
安全: "JWT + OAuth2.0"
notification-service:
职责: "邮件、短信、推送通知"
技术栈: "Java + Spring Cloud Stream"
通信: "订阅事件,异步发送"
# 基础设施服务
api-gateway:
职责: "请求路由、认证、限流"
技术栈: "Spring Cloud Gateway + Kong"
功能: ["负载均衡", "熔断", "监控"]
service-registry:
职责: "服务发现、健康检查"
技术栈: "Consul/Eureka"
config-service:
职责: "集中配置管理"
技术栈: "Spring Cloud Config"
3.3 服务间通信实现
// 1. 同步通信 - REST + Feign
// 订单服务调用库存服务(REST)
@Service
public class OrderServiceImpl {
@FeignClient(name = "inventory-service")
public interface InventoryClient {
@PostMapping("/api/inventory/deduct")
DeductResult deductStock(@RequestBody DeductRequest request);
@GetMapping("/api/inventory/stock/{skuId}")
StockInfo getStock(@PathVariable String skuId);
}
@Autowired
private InventoryClient inventoryClient;
public Order createOrder(OrderRequest request) {
// 调用库存服务扣减库存
DeductResult result = inventoryClient.deductStock(
new DeductRequest(request.getSkuId(), request.getQuantity())
);
if (!result.isSuccess()) {
throw new InsufficientStockException(result.getMessage());
}
// 创建订单...
}
}
// 2. 同步通信 - gRPC(高性能)
// proto定义
syntax = "proto3";
service InventoryService {
rpc DeductStock(DeductRequest) returns (DeductResponse);
rpc GetStock(StockQuery) returns (StockInfo);
}
message DeductRequest {
string sku_id = 1;
int32 quantity = 2;
string order_id = 3;
}
// 客户端调用
public class InventoryGrpcClient {
private final InventoryServiceGrpc.InventoryServiceBlockingStub stub;
public DeductResponse deductStock(String skuId, int quantity, String orderId) {
DeductRequest request = DeductRequest.newBuilder()
.setSkuId(skuId)
.setQuantity(quantity)
.setOrderId(orderId)
.build();
return stub.deductStock(request);
}
}
// 3. 异步通信 - 消息队列
// 订单服务发布订单创建事件
@Component
public class OrderEventPublisher {
@Autowired
private KafkaTemplate<String, Object> kafkaTemplate;
public void publishOrderCreated(Order order) {
OrderCreatedEvent event = OrderCreatedEvent.builder()
.orderId(order.getId())
.customerId(order.getCustomerId())
.totalAmount(order.getTotalAmount())
.items(order.getItems())
.timestamp(Instant.now())
.build();
kafkaTemplate.send("order-events", "created", event);
}
}
// 通知服务监听事件
@Component
public class NotificationService {
@KafkaListener(topics = "order-events")
public void handleOrderEvent(ConsumerRecord<String, OrderCreatedEvent> record) {
OrderCreatedEvent event = record.value();
// 发送订单确认邮件
emailService.sendOrderConfirmation(
event.getCustomerId(),
event.getOrderId()
);
// 发送短信通知
smsService.sendOrderSMS(
event.getCustomerId(),
"您的订单已创建,订单号: " + event.getOrderId()
);
}
}
3.4 数据一致性模式
// Saga模式:分布式事务管理
public class CreateOrderSaga {
private final List<SagaStep> steps = Arrays.asList(
new ReserveInventoryStep(),
new ProcessPaymentStep(),
new CreateOrderStep(),
new SendNotificationStep()
);
private final List<CompensationStep> compensations = Arrays.asList(
new ReleaseInventoryStep(),
new RefundPaymentStep(),
new CancelOrderStep()
);
public SagaResult execute(OrderRequest request) {
SagaContext context = new SagaContext(request);
try {
for (SagaStep step : steps) {
if (!step.execute(context)) {
// 执行失败,开始补偿
compensate(context, step);
return SagaResult.failed("Step failed: " + step.getName());
}
}
return SagaResult.success(context.getOrderId());
} catch (Exception e) {
compensate(context, null);
return SagaResult.failed(e.getMessage());
}
}
private void compensate(SagaContext context, SagaStep failedStep) {
// 从失败步骤开始逆向补偿
List<CompensationStep> stepsToCompensate = getStepsToCompensate(failedStep);
for (CompensationStep step : stepsToCompensate) {
try {
step.compensate(context);
} catch (Exception e) {
log.error("Compensation failed for step: " + step.getName(), e);
// 记录但继续其他补偿
}
}
}
}
// 事件溯源 + CQRS
// 命令端:处理写操作
@Service
@Transactional
public class OrderCommandService {
public OrderId createOrder(CreateOrderCommand command) {
// 1. 验证业务规则
validateCommand(command);
// 2. 生成领域事件
OrderCreatedEvent event = new OrderCreatedEvent(
UUID.randomUUID().toString(),
command.getCustomerId(),
command.getItems(),
Instant.now()
);
// 3. 保存事件到事件存储
eventStore.append(event.getOrderId(), event);
// 4. 发布事件
eventPublisher.publish(event);
return new OrderId(event.getOrderId());
}
}
// 查询端:处理读操作
@Service
public class OrderQueryService {
// 物化视图(读模型)
private final Map<String, OrderView> orderViewCache = new ConcurrentHashMap<>();
// 事件处理器:更新读模型
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
OrderView view = new OrderView(
event.getOrderId(),
event.getCustomerId(),
event.getItems(),
event.getTimestamp(),
OrderStatus.CREATED
);
orderViewCache.put(event.getOrderId(), view);
// 同时更新到读数据库
orderViewRepository.save(view);
}
public OrderView getOrder(String orderId) {
// 直接从读模型获取,性能好
return orderViewCache.get(orderId);
}
}
四、事件驱动架构
4.1 核心机制与原理
机制:事件生产-消费 + 消息代理
┌─────────┐ 发布事件 ┌─────────────┐ 订阅事件 ┌─────────┐
│生产者 A │─────────────▶│ 消息代理 │─────────────▶│消费者 X │
└─────────┘ │ (Kafka, │ └─────────┘
│ RabbitMQ) │ │
┌─────────┐ │ │ ┌─────────┐
│生产者 B │─────────────▶│ │─────────────▶│消费者 Y │
└─────────┘ └─────────────┘ └─────────┘
│ │
┌──────┴──────┐ ┌──────┴──────┐
│ 事件存储 │ │ 事件处理 │
│ (持久化) │ │ (业务逻辑) │
└─────────────┘ └─────────────┘
原理:
- 解耦:生产者不知道消费者,消费者不知道生产者
- 异步:非阻塞处理,提高系统吞吐量
- 可扩展:消费者可水平扩展
- 回放:事件存储支持重放历史
4.2 实例:电商订单事件流
// 事件定义
public interface DomainEvent {
String getAggregateId();
Instant getOccurredAt();
String getEventType();
}
// 具体事件
public class OrderCreatedEvent implements DomainEvent {
private String orderId;
private String customerId;
private List<OrderItem> items;
private BigDecimal totalAmount;
private Instant createdAt;
// getters, constructors...
}
public class PaymentProcessedEvent implements DomainEvent {
private String orderId;
private String paymentId;
private BigDecimal amount;
private PaymentStatus status;
private Instant processedAt;
}
public class InventoryReservedEvent implements DomainEvent {
private String orderId;
private String skuId;
private int quantity;
private Instant reservedAt;
}
// 事件处理器
@Component
public class OrderEventHandler {
// 处理订单创建事件
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("Processing order created: {}", event.getOrderId());
// 1. 更新订单读模型
orderViewRepository.updateFromEvent(event);
// 2. 发送到分析系统
analyticsService.trackOrderCreated(event);
// 3. 触发后续流程
eventPublisher.publish(new ProcessPaymentCommand(event.getOrderId()));
}
// 处理支付成功事件
@EventListener
public void handlePaymentProcessed(PaymentProcessedEvent event) {
if (event.getStatus() == PaymentStatus.SUCCESS) {
// 1. 更新订单状态
orderService.confirmPayment(event.getOrderId(), event.getPaymentId());
// 2. 预留库存
eventPublisher.publish(new ReserveInventoryCommand(
event.getOrderId(),
getOrderItems(event.getOrderId())
));
// 3. 发送确认通知
notificationService.sendPaymentConfirmation(event.getOrderId());
}
}
}
// 事件溯源实现
@Component
public class EventSourcedOrder {
private String orderId;
private List<DomainEvent> changes = new ArrayList<>();
private OrderState state = new OrderState();
public EventSourcedOrder(String orderId) {
this.orderId = orderId;
}
// 从事件流重建
public static EventSourcedOrder rebuild(String orderId, List<DomainEvent> events) {
EventSourcedOrder order = new EventSourcedOrder(orderId);
events.forEach(order::apply);
return order;
}
// 创建订单
public void create(String customerId, List<OrderItem> items) {
OrderCreatedEvent event = new OrderCreatedEvent(
orderId, customerId, items, Instant.now()
);
apply(event);
changes.add(event);
}
// 应用事件(改变状态)
private void apply(DomainEvent event) {
if (event instanceof OrderCreatedEvent) {
apply((OrderCreatedEvent) event);
} else if (event instanceof PaymentProcessedEvent) {
apply((PaymentProcessedEvent) event);
}
// ... 其他事件
}
private void apply(OrderCreatedEvent event) {
state.setCustomerId(event.getCustomerId());
state.setItems(event.getItems());
state.setStatus(OrderStatus.CREATED);
state.setTotalAmount(calculateTotal(event.getItems()));
}
// 获取当前状态
public OrderState getState() {
return state.copy(); // 返回副本,避免直接修改
}
// 获取未提交的事件
public List<DomainEvent> getUncommittedChanges() {
return new ArrayList<>(changes);
}
// 标记事件已提交
public void markChangesAsCommitted() {
changes.clear();
}
}
五、领域驱动设计(DDD)
5.1 核心机制与原理
机制:限界上下文 + 领域模型 + 通用语言
战略设计(宏观) 战术设计(微观)
├── 限界上下文 ├── 实体(Entity)
├── 上下文映射 ├── 值对象(Value Object)
├── 通用语言 ├── 聚合(Aggregate)
└── 子域/核心域 ├── 领域服务(Domain Service)
├── 仓储(Repository)
└── 领域事件(Domain Event)
原理:
- 通用语言:业务与技术共享的精确语言
- 领域模型:捕获业务复杂性的对象模型
- 限界上下文:模型的有效边界
- 分层架构:分离领域逻辑与技术实现
5.2 实例:电商订单领域建模
// 1. 限界上下文识别
// 订单上下文 vs 库存上下文 vs 支付上下文
@BoundedContext(name = "订单", domain = "核心域")
public class OrderContext {
// 领域模型定义
}
// 2. 聚合根设计
@Entity
@AggregateRoot
public class Order {
@Id
private OrderId id;
@Embedded
private CustomerId customerId;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderLine> orderLines;
@Embedded
private Money totalAmount;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@Embedded
private ShippingAddress shippingAddress;
// 关键:聚合内一致性保护
public void addItem(Product product, int quantity) {
// 业务规则:已支付的订单不能添加商品
if (this.status == OrderStatus.PAID) {
throw new IllegalStateException("Cannot add items to a paid order");
}
OrderLine line = new OrderLine(product, quantity);
this.orderLines.add(line);
// 聚合内计算总价
recalculateTotal();
// 发布领域事件
DomainEvents.raise(new OrderLineAddedEvent(
this.id, product.getId(), quantity
));
}
// 支付订单
public void pay(PaymentId paymentId, Money amount) {
// 业务规则:金额必须匹配
if (!this.totalAmount.equals(amount)) {
throw new IllegalArgumentException("Payment amount does not match order total");
}
// 业务规则:只有特定状态的订单可以支付
if (!this.status.canTransitionTo(OrderStatus.PAID)) {
throw new IllegalStateException("Order cannot be paid in current state");
}
this.status = OrderStatus.PAID;
// 发布领域事件
DomainEvents.raise(new OrderPaidEvent(this.id, paymentId, amount));
}
// 私有方法:聚合内计算
private void recalculateTotal() {
this.totalAmount = this.orderLines.stream()
.map(OrderLine::calculateLineTotal)
.reduce(Money.ZERO, Money::add);
}
}
// 3. 值对象(不可变)
@Embeddable
public class Money implements ValueObject {
private final BigDecimal amount;
private final Currency currency;
public Money(BigDecimal amount, Currency currency) {
this.amount = amount.setScale(2, RoundingMode.HALF_EVEN);
this.currency = currency;
}
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new IllegalArgumentException("Cannot add different currencies");
}
return new Money(this.amount.add(other.amount), this.currency);
}
// 值对象相等性比较
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Money money = (Money) o;
return amount.compareTo(money.amount) == 0 &&
currency.equals(money.currency);
}
@Override
public int hashCode() {
return Objects.hash(amount, currency);
}
}
// 4. 领域服务(处理跨聚合逻辑)
@Service
public class OrderPlacementService implements DomainService {
private final OrderRepository orderRepository;
private final InventoryService inventoryService;
private final CustomerCreditService creditService;
@Transactional
public OrderId placeOrder(PlaceOrderCommand command) {
// 验证客户信用
CustomerCredit credit = creditService.getCredit(command.getCustomerId());
if (!credit.hasSufficientCredit(command.getTotalAmount())) {
throw new InsufficientCreditException("Customer credit insufficient");
}
// 检查库存
for (OrderItem item : command.getItems()) {
StockInfo stock = inventoryService.getStock(item.getProductId());
if (stock.getAvailableQuantity() < item.getQuantity()) {
throw new InsufficientStockException(
"Insufficient stock for product: " + item.getProductId()
);
}
}
// 创建订单
Order order = new Order(
OrderId.generate(),
command.getCustomerId(),
command.getShippingAddress()
);
for (OrderItem item : command.getItems()) {
order.addItem(item.getProduct(), item.getQuantity());
}
// 保存订单
orderRepository.save(order);
// 预扣库存(跨上下文协作)
inventoryService.reserveStock(command);
return order.getId();
}
}
// 5. 仓储接口(领域层定义)
public interface OrderRepository {
Order findById(OrderId id);
List<Order> findByCustomerId(CustomerId customerId);
Order save(Order order);
void delete(OrderId id);
// 特定查询方法
List<Order> findPendingOrders(Date fromDate, Date toDate);
int countOrdersByStatus(OrderStatus status);
}
// 6. 领域事件
public class OrderPlacedEvent implements DomainEvent {
private final OrderId orderId;
private final CustomerId customerId;
private final List<OrderItem> items;
private final Instant occurredAt;
public OrderPlacedEvent(Order order) {
this.orderId = order.getId();
this.customerId = order.getCustomerId();
this.items = order.getItems();
this.occurredAt = Instant.now();
}
// getters...
}
// 7. 应用服务(编排领域对象)
@Service
@Transactional
public class OrderApplicationService {
private final OrderRepository orderRepository;
private final OrderPlacementService placementService;
private final PaymentService paymentService;
private final EventPublisher eventPublisher;
public OrderDTO createOrder(CreateOrderRequest request) {
// 1. 转换请求为命令对象
PlaceOrderCommand command = toCommand(request);
// 2. 调用领域服务
OrderId orderId = placementService.placeOrder(command);
// 3. 处理支付
PaymentResult payment = paymentService.processPayment(
new PaymentRequest(orderId, command.getTotalAmount())
);
// 4. 更新订单状态
Order order = orderRepository.findById(orderId);
order.confirmPayment(payment.getTransactionId());
orderRepository.save(order);
// 5. 发布集成事件
eventPublisher.publish(new OrderConfirmedEvent(order));
// 6. 返回DTO
return OrderMapper.toDTO(order);
}
}
5.3 DDD战术模式映射表
| 模式 | 目的 | 实例 |
|---|---|---|
| 实体 | 具有唯一标识和生命周期的对象 | Order, Customer, Product |
| 值对象 | 描述属性,没有唯一标识 | Money, Address, OrderLine |
| 聚合 | 一组相关对象的边界,根实体控制访问 | Order(聚合根)+ OrderLine(内部对象) |
| 仓储 | 管理聚合持久化,提供集合式接口 | OrderRepository, CustomerRepository |
| 工厂 | 封装复杂对象创建逻辑 | OrderFactory, PaymentFactory |
| 领域服务 | 处理不适合放在实体/值对象的逻辑 | OrderPlacementService, TaxCalculationService |
| 领域事件 | 记录领域中的重要发生事件 | OrderPlacedEvent, PaymentProcessedEvent |
| 模块 | 组织相关领域对象 | order.module, inventory.module |
六、架构组合与演进
6.1 混合架构模式
# 现代云原生应用架构示例
架构风格: "微服务 + 事件驱动 + DDD + CQRS"
服务分解:
命令端服务(写模型):
架构: "DDD聚合 + 事件溯源"
通信: "同步REST/gRPC"
数据: "事件存储 + 读模型物化"
查询端服务(读模型):
架构: "CQRS查询模型"
通信: "GraphQL/REST"
数据: "物化视图(Elasticsearch/Redis)"
事件处理服务:
架构: "事件驱动 + 流处理"
通信: "Kafka消息"
处理: "Flink/Spark Streaming"
边缘服务:
架构: "API网关 + BFF(Backend for Frontend)"
通信: "GraphQL + WebSocket"
功能: "聚合、协议转换"
部署拓扑:
开发环境: "Docker Compose (单体容器化)"
测试环境: "Kubernetes命名空间隔离"
生产环境: "多集群Kubernetes + 服务网格"
6.2 架构演进策略
// 从单体到微服务的演进示例
public class ArchitectureEvolution {
// 阶段1: 模块化单体
public void stage1_modularMonolith() {
// 单一代码库,模块化结构
ProjectStructure {
modules: [
"order-module",
"inventory-module",
"payment-module",
"user-module"
],
deployment: "单一WAR包",
database: "共享数据库,按模块分表",
communication: "进程内方法调用"
}
}
// 阶段2: 服务化架构
public void stage2_serviceOriented() {
// 逻辑服务拆分,物理部署仍在一起
ProjectStructure {
services: [
"OrderService",
"InventoryService",
"PaymentService"
],
deployment: "单一进程,多服务实例",
database: "共享数据库,按服务分表",
communication: "进程内RPC/消息"
}
}
// 阶段3: 微服务架构
public void stage3_microservices() {
// 物理隔离的服务
ProjectStructure {
services: [
"order-service (独立进程)",
"inventory-service (独立进程)",
"payment-service (独立进程)"
],
deployment: "容器化独立部署",
database: "每个服务独立数据库",
communication: "HTTP/gRPC + 消息队列"
}
}
}
6.3 架构决策记录(ADR)
# ADR 002: 采用事件驱动架构处理订单流程
## 状态
已采纳
## 决策背景
当前订单处理流程存在以下问题:
1. 同步调用导致服务紧耦合
2. 高峰期性能瓶颈明显
3. 新功能添加困难,需要修改多个服务
## 决策内容
采用事件驱动架构重构订单处理流程:
1. 订单创建后发布`OrderCreatedEvent`
2. 库存服务监听事件,异步预留库存
3. 支付服务监听事件,异步处理支付
4. 通知服务监听事件,异步发送通知
## 架构方案
订单服务 → 发布事件 → Kafka → 多个消费者并行处理
## 技术选型
- 消息代理: Apache Kafka
- 事件格式: CloudEvents + Avro Schema
- 消费者组: Spring Cloud Stream
## 预期效果
- 解耦服务,独立扩展
- 提高系统吞吐量
- 支持事件溯源和回放
- 简化新功能添加
## 风险与缓解
- 事件顺序问题: 使用Kafka分区键保证同一订单事件顺序
- 事件丢失: 配置Kafka ACKS=all
- 最终一致性: 设计补偿机制(Saga模式)
七、选择指南与最佳实践
7.1 架构选择决策树
开始
├─ 系统是否简单且团队小?
│ ├─ 是 → 选择分层架构/MVC
│ └─ 否 → 继续
│
├─ 业务逻辑是否复杂多变?
│ ├─ 是 → 采用DDD设计领域模型
│ └─ 否 → 继续
│
├─ 是否需要独立扩展组件?
│ ├─ 是 → 微服务架构
│ └─ 否 → 继续
│
├─ 是否大量异步事件处理?
│ ├─ 是 → 事件驱动架构
│ └─ 否 → 继续
│
├─ 是否为数据处理流水线?
│ ├─ 是 → 管道-过滤器架构
│ └─ 否 → 继续
│
└─ 是否需要集成多个异构系统?
├─ 是 → SOA架构
└─ 否 → 分层架构
7.2 架构模式组合策略
-
分层 + DDD:适合复杂业务系统
- 上层:表示层(控制器)
- 中层:应用层(用例编排)+ 领域层(业务逻辑)
- 下层:基础设施层(持久化、外部服务)
-
微服务 + 事件驱动:适合高并发、可扩展系统
- 微服务间通过事件异步通信
- 每个微服务内部使用分层架构
- 关键服务内部使用DDD
-
CQRS + 事件溯源:适合需要完整审计和复杂查询的系统
- 命令端:DDD + 事件存储
- 查询端:物化视图 + 缓存
- 同步机制:事件发布/订阅
7.3 核心建议
- 从简单开始:不要一开始就使用最复杂的架构
- 渐进式演进:随着业务增长和团队扩大,逐步演进架构
- 关注边界:清晰的边界是良好架构的关键
- 保持一致性:团队内部对架构的理解和执行要一致
- 持续重构:架构不是一次性的,需要持续改进
- 监控与度量:用数据驱动架构决策和优化
记住,没有"最好"的架构,只有"最适合"当前和可预见未来需求的架构。架构选择是权衡的艺术,需要平衡业务需求、技术约束、团队能力和运维成本。
2793

被折叠的 条评论
为什么被折叠?



