随着微服务架构的普及,领域驱动设计(DDD)在复杂业务系统中的应用越来越广泛。本文将结合最新技术栈(Spring Boot 3.x、Spring Data JPA 3.x、Lombok等),通过一个电商订单系统的实例,详细讲解DDD分层架构的具体实现。
采用模块化设计,按DDD分层思想组织代码结构:
order-service/
├── src/main/java/com/example/order/
│ ├── application/ // 应用层
│ │ ├── command/ // 命令对象
│ │ ├── dto/ // 数据传输对象
│ │ ├── service/ // 应用服务
│ │ └── mapper/ // DTO与领域对象映射
│ ├── domain/ // 领域层
│ │ ├── model/ // 领域模型
│ │ │ ├── entity/ // 实体
│ │ │ ├── vo/ // 值对象
│ │ │ └── aggregate/ // 聚合根
│ │ ├── repository/ // 仓储接口
│ │ └── service/ // 领域服务
│ ├── infrastructure/ // 基础设施层
│ │ ├── persistence/ // 持久化实现
│ │ ├── messaging/ // 消息组件
│ │ └── config/ // 配置类
│ └── interfaces/ // 用户接口层
│ ├── rest/ // REST接口
│ └── facade/ // 外部服务接口
└── src/main/resources/
├── application.yml // 应用配置
└── db/migration/ // 数据库迁移脚本
领域层是系统的核心,包含了所有业务规则和领域模型。以订单为例:
值对象实现:
// 货币值对象
@Value
public class Money {
@NonNull
BigDecimal amount;
@NonNull
Currency currency;
// 确保货币值不能为负
public Money(BigDecimal amount, Currency currency) {
if (amount.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("金额不能为负数");
}
this.amount = amount;
this.currency = currency;
}
// 金额加法操作
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new IllegalArgumentException("货币类型不匹配");
}
return new Money(this.amount.add(other.amount), this.currency);
}
}
实体与聚合根实现:
// 订单项实体
@Entity
@Table(name = "order_item")
@Data
@NoArgsConstructor
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String productId;
private String productName;
private int quantity;
@Embedded
private Money unitPrice;
// 计算订单项总价
public Money calculateTotal() {
return new Money(
unitPrice.getAmount().multiply(BigDecimal.valueOf(quantity)),
unitPrice.getCurrency()
);
}
}
// 订单聚合根
@Entity
@Table(name = "orders")
@Data
@NoArgsConstructor
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String orderNumber;
private String customerId;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@Embedded
private Money totalAmount;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "order_id")
private List<OrderItem> items = new ArrayList<>();
// 领域行为:添加订单项
public void addItem(OrderItem item) {
this.items.add(item);
recalculateTotal();
}
// 领域行为:重新计算订单总价
private void recalculateTotal() {
this.totalAmount = items.stream()
.map(OrderItem::calculateTotal)
.reduce(new Money(BigDecimal.ZERO, Currency.getInstance("CNY")), Money::add);
}
// 领域行为:确认订单
public void confirm() {
if (this.status != OrderStatus.CREATED) {
throw new IllegalStateException("只有创建状态的订单可以确认");
}
this.status = OrderStatus.CONFIRMED;
}
}
领域服务与仓储接口:
// 订单仓储接口
public interface OrderRepository {
Order save(Order order);
Optional<Order> findById(Long id);
Optional<Order> findByOrderNumber(String orderNumber);
}
// 订单领域服务(处理跨聚合的业务逻辑)
@Service
@RequiredArgsConstructor
public class OrderDomainService {
private final InventoryService inventoryService;
// 检查订单商品库存
public boolean checkInventory(Order order) {
return order.getItems().stream()
.allMatch(item -> inventoryService.hasStock(item.getProductId(), item.getQuantity()));
}
}
应用层负责协调领域对象完成业务用例,处理事务和权限:
// 命令对象(封装创建订单的请求参数)
@Data
public class CreateOrderCommand {
@NotBlank(message = "客户ID不能为空")
private String customerId;
@NotEmpty(message = "订单项不能为空")
private List<OrderItemCommand> items;
}
// 应用服务
@Service
@RequiredArgsConstructor
@Transactional
public class OrderApplicationService {
private final OrderRepository orderRepository;
private final OrderDomainService orderDomainService;
private final OrderMapper orderMapper;
// 创建订单用例
public OrderDTO createOrder(CreateOrderCommand command) {
// 1. 转换命令为领域对象
Order order = orderMapper.toDomain(command);
// 2. 生成订单号
order.setOrderNumber(generateOrderNumber());
order.setStatus(OrderStatus.CREATED);
// 3. 业务规则校验
if (!orderDomainService.checkInventory(order)) {
throw new InsufficientInventoryException("商品库存不足");
}
// 4. 保存订单
Order savedOrder = orderRepository.save(order);
// 5. 发布领域事件(后续通过消息队列实现)
// orderEventPublisher.publish(new OrderCreatedEvent(savedOrder));
// 6. 转换为DTO返回
return orderMapper.toDTO(savedOrder);
}
// 确认订单用例
public void confirmOrder(String orderNumber) {
Order order = orderRepository.findByOrderNumber(orderNumber)
.orElseThrow(() -> new OrderNotFoundException("订单不存在: " + orderNumber));
order.confirm();
orderRepository.save(order);
}
// 生成唯一订单号
private String generateOrderNumber() {
return "ORD" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
+ RandomStringUtils.randomNumeric(4);
}
}
基础设施层提供技术支持,实现领域层定义的接口:
// 订单仓储JPA实现
@Repository
public interface JpaOrderRepository extends OrderRepository, JpaRepository<Order, Long> {
@Override
Optional<Order> findByOrderNumber(String orderNumber);
}
// 库存服务(外部服务调用实现)
@Service
public class InventoryServiceImpl implements InventoryService {
private final RestTemplate restTemplate;
@Override
public boolean hasStock(String productId, int quantity) {
// 调用库存服务API检查库存
String url = "http://inventory-service/api/inventory/check?productId=" + productId + "&quantity=" + quantity;
try {
return restTemplate.getForObject(url, Boolean.class);
} catch (Exception e) {
log.error("检查库存失败", e);
return false;
}
}
}
用户接口层处理HTTP请求和响应:
@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderApplicationService orderApplicationService;
@PostMapping
public ResponseEntity<OrderDTO> createOrder(@Valid @RequestBody CreateOrderCommand command) {
OrderDTO orderDTO = orderApplicationService.createOrder(command);
return ResponseEntity
.created(URI.create("/api/orders/" + orderDTO.getOrderNumber()))
.body(orderDTO);
}
@PutMapping("/{orderNumber}/confirm")
public ResponseEntity<Void> confirmOrder(@PathVariable String orderNumber) {
orderApplicationService.confirmOrder(orderNumber);
return ResponseEntity.noContent().build();
}
@GetMapping("/{orderNumber}")
public ResponseEntity<OrderDTO> getOrder(@PathVariable String orderNumber) {
return orderApplicationService.getOrderByNumber(orderNumber)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
}
@Embedded
和@Embeddable
注解将值对象嵌入实体中,避免数据库表膨胀。@Transactional
注解管理事务边界,确保业务操作的原子性。基于DDD的分层架构通过清晰的职责划分,将业务逻辑与技术实现分离,使系统更具可维护性和扩展性。在实际项目中,应根据业务复杂度灵活调整DDD的实现方式,不必生搬硬套所有概念。
随着微服务架构的发展,DDD与微服务的结合越来越紧密,通过领域边界划分微服务可以有效降低服务间的耦合,这也是DDD在现代软件开发中越来越受欢迎的重要原因。
Java,DDD 分层架构,领域驱动设计,Java 架构原理,DDD 核心原理,项目落地实操,Java 实操指南,分层架构设计,DDD 项目落地,Java 开发指南,领域驱动设计原理,DDD 最新实操,Java 分层实践,架构落地技巧,DDD 全指南
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。