五、架构思维:从代码到系统
设计模式解决的是类级别的问题,而架构思维解决的是系统级别的问题。
5.1 架构设计的核心原则
5.2 分层架构(Layered Architecture)
分层架构(经典四层):
┌─────────────────────────────────────┐
│ 表现层 (Presentation) │ ← Controller, JSP, REST API
├─────────────────────────────────────┤
│ 应用层 (Application) │ ← Service, 业务编排
├─────────────────────────────────────┤
│ 领域层 (Domain) │ ← Entity, 核心业务逻辑
├─────────────────────────────────────┤
│ 基础设施层 (Infrastructure) │ ← Repository, 数据库访问
└─────────────────────────────────────┘
依赖方向: 上层依赖下层,下层对上层无感知
// 分层架构示例
// 表现层
@RestController
public class OrderController {
@Autowired
private OrderApplicationService orderService;
@PostMapping("/orders")
public OrderResponse createOrder(@RequestBody CreateOrderRequest request) {
return orderService.createOrder(request);
}
}
// 应用层
@Service
public class OrderApplicationService {
@Autowired
private OrderDomainService orderDomainService;
@Autowired
private OrderRepository orderRepository;
@Autowired
private PaymentGateway paymentGateway;
@Transactional
public OrderResponse createOrder(CreateOrderRequest request) {
// 应用层编排
Order order = Order.create(request.getUserId(), request.getItems());
// 调用领域服务
orderDomainService.calculateDiscount(order);
// 调用基础设施
orderRepository.save(order);
// 外部系统调用
PaymentResult payment = paymentGateway.charge(order.getTotalAmount());
order.markAsPaid(payment.getTransactionId());
orderRepository.save(order);
return OrderResponse.from(order);
}
}
// 领域层
public class Order {
private String orderId;
private String userId;
private List<OrderItem> items;
private OrderStatus status;
private BigDecimal totalAmount;
// 领域逻辑(核心业务规则)
public static Order create(String userId, List<OrderItem> items) {
Order order = new Order();
order.orderId = generateOrderId();
order.userId = userId;
order.items = items;
order.status = OrderStatus.PENDING;
order.totalAmount = calculateTotal(items);
return order;
}
public void markAsPaid(String transactionId) {
if (this.status != OrderStatus.PENDING) {
throw new IllegalStateException("Order cannot be paid: status is " + this.status);
}
this.status = OrderStatus.PAID;
// 记录支付信息...
}
}
// 基础设施层
@Repository
public class OrderRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public void save(Order order) {
jdbcTemplate.update("INSERT INTO orders ...", order.getOrderId(), ...);
}
}
5.3 六边形架构(Hexagonal Architecture / 端口适配器)
六边形架构强调业务逻辑与外部系统的隔离,通过端口(Port)和适配器(Adapter)实现。
┌─────────────────────────────────────────────────────────────────┐
│ 六边形架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ HTTP适配器 │ │ 数据库适配器 │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 端口 │ │
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ 业务核心(领域模型) │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ │ 端口 │ │
│ └─────────────────────────────────────────────────┘ │
│ ▲ ▲ │
│ │ │ │
│ ┌──────┴──────┐ ┌──────┴──────┐ │
│ │ 消息适配器 │ │ 邮件适配器 │ │
│ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
// 端口接口(内)
public interface OrderService {
Order createOrder(OrderCommand command);
Order getOrder(String orderId);
void cancelOrder(String orderId);
}
public interface PaymentService {
PaymentResult charge(BigDecimal amount, PaymentMethod method);
}
// 领域模型(核心业务)
public class Order {
// 纯业务逻辑,不依赖任何外部框架
private String id;
private List<OrderLine> lines;
private OrderStatus status;
public void addItem(Product product, int quantity) {
lines.add(new OrderLine(product, quantity));
recalculateTotal();
}
public void cancel() {
if (status == OrderStatus.SHIPPED) {
throw new IllegalStateException("Cannot cancel shipped order");
}
this.status = OrderStatus.CANCELLED;
}
private void recalculateTotal() {
this.total = lines.stream()
.map(line -> line.getProduct().getPrice().multiply(BigDecimal.valueOf(line.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
// 端口实现(外)
@RestController
public class OrderController implements OrderService { // 实现端口接口
private final OrderApplication orderApp;
@Override
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderCommand command) {
return orderApp.createOrder(command);
}
}
@Repository
public class OrderRepository implements OrderPort { // 另一个端口实现
// 数据库访问逻辑
}
5.4 CQRS(命令查询职责分离)
CQRS将读操作和写操作分离为不同的模型。
// 命令(写模型)
public class CreateOrderCommand {
private String userId;
private List<OrderItemDto> items;
}
@Service
public class OrderCommandService {
@Autowired
private OrderRepository writeRepository;
@Autowired
private EventPublisher eventPublisher;
@Transactional
public String handle(CreateOrderCommand command) {
// 写模型关注业务规则和事务一致性
Order order = Order.create(command.getUserId(), command.getItems());
order.validate();
writeRepository.save(order);
// 发布领域事件,用于更新读模型
eventPublisher.publish(new OrderCreatedEvent(order.getId()));
return order.getId();
}
}
// 查询(读模型)
@RestController
public class OrderQueryService {
@Autowired
private OrderReadRepository readRepository; // 可以是Elasticsearch或其他
@GetMapping("/orders/{id}")
public OrderReadModel getOrder(@PathVariable String id) {
// 读模型可以完全去规范化,优化查询性能
return readRepository.findById(id);
}
@GetMapping("/orders")
public Page<OrderReadModel> listOrders(OrderQueryParams params) {
// 复杂的查询和聚合
return readRepository.search(params);
}
}
// 读模型(去规范化)
@Document(indexName = "orders")
public class OrderReadModel {
private String id;
private String userId;
private String userName; // 冗余用户姓名,避免JOIN
private List<OrderItemReadModel> items;
private String status;
private LocalDateTime createdAt;
// 不需要所有业务字段,只存查询需要的字段
}
5.5 事件驱动架构(Event-Driven Architecture)
事件驱动架构通过异步事件解耦服务间的通信。
// 领域事件定义
public abstract class DomainEvent {
private final String eventId = UUID.randomUUID().toString();
private final LocalDateTime occurredAt = LocalDateTime.now();
public String getEventId() { return eventId; }
public LocalDateTime getOccurredAt() { return occurredAt; }
}
public class OrderCreatedEvent extends DomainEvent {
private final String orderId;
private final String userId;
private final BigDecimal amount;
public OrderCreatedEvent(String orderId, String userId, BigDecimal amount) {
this.orderId = orderId;
this.userId = userId;
this.amount = amount;
}
// getters
}
public class OrderPaidEvent extends DomainEvent {
private final String orderId;
private final String transactionId;
// ...
}
// 事件发布器
@Service
public class DomainEventPublisher {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Autowired
private KafkaTemplate<String, Object> kafkaTemplate;
@EventListener
public void handleDomainEvent(DomainEvent event) {
// 本地事件(同一JVM内)
applicationEventPublisher.publishEvent(event);
// 分布式事件(跨服务)
kafkaTemplate.send("order-events", event.getClass().getSimpleName(), event);
}
}
// 事件处理器(本地)
@Component
@EventListener
public class InventoryEventHandler {
public void handleOrderPaid(OrderPaidEvent event) {
// 扣减库存
inventoryService.deductStock(event.getOrderId());
}
}
// 事件处理器(远程)
@Component
@KafkaListener(topics = "order-events")
public class NotificationEventHandler {
@KafkaHandler
public void handleOrderCreated(OrderCreatedEvent event) {
// 发送确认邮件
emailService.sendOrderConfirmation(event.getUserId(), event.getOrderId());
}
@KafkaHandler
public void handleOrderPaid(OrderPaidEvent event) {
// 发送支付成功通知
notificationService.sendPaymentNotification(event.getUserId());
}
}