Java基于DDD分层架构的最新实操指南

随着微服务架构的普及,领域驱动设计(DDD)在复杂业务系统中的应用越来越广泛。本文将结合最新技术栈(Spring Boot 3.x、Spring Data JPA 3.x、Lombok等),通过一个电商订单系统的实例,详细讲解DDD分层架构的具体实现。

一、技术栈选择

  • 核心框架:Spring Boot 3.2.x(支持Jakarta EE 9+)
  • ORM框架:Spring Data JPA 3.2.x
  • 简化代码:Lombok 1.18.x
  • 验证框架:Jakarta Validation 3.0
  • 数据库:PostgreSQL 16(支持JSON类型,适合存储值对象)
  • 构建工具:Maven 3.9.x

二、项目结构设计

采用模块化设计,按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/          // 数据库迁移脚本

三、各层具体实现

1. 领域层实现(核心业务)

领域层是系统的核心,包含了所有业务规则和领域模型。以订单为例:

值对象实现

// 货币值对象
@Value
public class Money {@NonNullBigDecimal amount;@NonNullCurrency 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;@Embeddedprivate 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;@Embeddedprivate 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()));}
}
2. 应用层实现

应用层负责协调领域对象完成业务用例,处理事务和权限:

// 命令对象(封装创建订单的请求参数)
@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);}
}
3. 基础设施层实现

基础设施层提供技术支持,实现领域层定义的接口:

// 订单仓储JPA实现
@Repository
public interface JpaOrderRepository extends OrderRepository, JpaRepository<Order, Long> {@OverrideOptional<Order> findByOrderNumber(String orderNumber);
}// 库存服务(外部服务调用实现)
@Service
public class InventoryServiceImpl implements InventoryService {private final RestTemplate restTemplate;@Overridepublic 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;}}
}
4. 用户接口层实现

用户接口层处理HTTP请求和响应:

@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {private final OrderApplicationService orderApplicationService;@PostMappingpublic 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());}
}

四、关键技术点说明

  1. 值对象的持久化:使用@Embedded@Embeddable注解将值对象嵌入实体中,避免数据库表膨胀。

  2. 聚合根的设计:订单作为聚合根,负责维护订单项的一致性,所有对订单项的操作都通过订单聚合根完成。

  3. 领域事件处理:在应用服务中发布领域事件,通过Spring的事件机制或消息队列(如Kafka)实现领域事件的异步处理,解耦系统组件。

  4. 事务管理:在应用服务层使用@Transactional注解管理事务边界,确保业务操作的原子性。

  5. 对象映射:使用MapStruct框架实现DTO与领域对象之间的映射,避免手动编写大量getter/setter代码。

五、总结

基于DDD的分层架构通过清晰的职责划分,将业务逻辑与技术实现分离,使系统更具可维护性和扩展性。在实际项目中,应根据业务复杂度灵活调整DDD的实现方式,不必生搬硬套所有概念。

随着微服务架构的发展,DDD与微服务的结合越来越紧密,通过领域边界划分微服务可以有效降低服务间的耦合,这也是DDD在现代软件开发中越来越受欢迎的重要原因。


Java,DDD 分层架构,领域驱动设计,Java 架构原理,DDD 核心原理,项目落地实操,Java 实操指南,分层架构设计,DDD 项目落地,Java 开发指南,领域驱动设计原理,DDD 最新实操,Java 分层实践,架构落地技巧,DDD 全指南