六边形架构(DDD)完整落地实战:从理论到可运行代码
2026/6/7 10:51:35 网站建设 项目流程

在传统分层架构(Controller → Service → DAO)中,业务代码常常被接口、第三方调用、数据库、消息中间件等外部技术细节裹挟。一旦数据源、对接渠道、外部系统发生变更,核心业务就要大面积改代码,测试困难、迭代风险高。

什么是六边形架构?六边形架构(Hexagonal Architecture)也叫端口与适配器架构,是 DDD 领域驱动设计最经典的落地架构之一。

本文实现可落地、可用于生产的六边形架构,以订单创建场景作为案例,语言通俗、代码完整,适配 Java/SpringBoot 主流技术栈。

一、实战场景说明

实现一个极简但完整的业务:用户创建订单 → 校验订单 → 保存订单 → 发送通知

严格遵守六边形架构规则:

  1. 领域层完全纯净,不依赖任何框架、DB、第三方接口
  2. 依赖方向永远向内,外层依赖内层
  3. 端口 = 接口,适配器 = 实现,业务与技术彻底隔离

二、项目包结构(六边形标准结构)

Plain Text
com.order
├── domain/ # 内核:领域层(纯业务,无任何外部依赖)
│ ├── entity/ # 领域实体
│ └── service/ # 领域服务(核心业务规则)
├── application/ # 内核:应用层(流程编排)
│ └── service/ # 应用服务
├── port/ # 端口:抽象接口(业务定义能力)
│ ├── inbound/ # 入站端口:外部调用系统
│ └── outbound/ # 出站端口:系统调用外部
├── adapter/ # 适配器:具体实现(技术细节)
│ ├── inbound/ # 入站适配器:Controller、RPC、Job
│ └── outbound/ # 出站适配器:DB、Redis、第三方接口
└── OrderApplication.java # 启动类

一句话看懂
domain + application = 系统心脏
port = 插座(抽象)
adapter = 插头(实现)

三、代码实现(完整可复制)

1. 领域层(最内层,纯业务,零依赖)

1.1 领域实体:Order.java

java
package com.order.domain.entity;

import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
* 领域实体:只包含业务属性与业务行为
* 无任何框架注解、无DB注解、无第三方依赖
*/
@Data
public class Order {
private String orderId;
private String userId;
private BigDecimal amount;
private LocalDateTime createTime;

// 领域行为:订单创建规则
public void create() {
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new RuntimeException("订单金额必须大于0");
}
this.createTime = LocalDateTime.now();
}
}

1.2 领域服务:OrderDomainService.java

java
package com.order.domain.service;

import com.order.domain.entity.Order;
import org.springframework.stereotype.Service;

/**
* 领域服务:处理跨实体的核心业务规则
* 纯业务逻辑,不处理技术、不操作DB
*/
@Service
public class OrderDomainService {

public void createOrder(Order order) {
// 执行业务行为
order.create();
// 可继续添加:库存校验、价格计算、风控规则等纯业务逻辑
}
}

2. 端口层(抽象接口:定义能力,不做实现)

2.1 入站端口(给外部调用)

java
package com.order.port.inbound;

import com.order.domain.entity.Order;

public interface CreateOrderUseCase {
Order createOrder(Order order);
}

2.2 出站端口(定义需要外部能力:DB、消息等)

java
package com.order.port.outbound;

import com.order.domain.entity.Order;

// 订单仓储端口(抽象)
public interface OrderRepositoryPort {
Order save(Order order);
}

java
package com.order.port.outbound;

// 通知端口(抽象)
public interface NotifyPort {
void sendNotify(String orderId);
}

3. 应用层(流程编排,不写业务规则)

java
package com.order.application.service;

import com.order.domain.entity.Order;
import com.order.domain.service.OrderDomainService;
import com.order.port.inbound.CreateOrderUseCase;
import com.order.port.outbound.NotifyPort;
import com.order.port.outbound.OrderRepositoryPort;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
* 应用服务:只做流程编排,不写核心业务规则
* 依赖:领域服务 + 出站端口(抽象接口)
*/
@Service
@RequiredArgsConstructor
public class OrderApplicationService implements CreateOrderUseCase {

private final OrderDomainService orderDomainService;
private final OrderRepositoryPort orderRepositoryPort;
private final NotifyPort notifyPort;

@Override
@Transactional(rollbackFor = Exception.class)
public Order createOrder(Order order) {
// 1. 领域层执行业务规则
orderDomainService.createOrder(order);

// 2. 调用出站端口(保存订单,具体实现由适配器完成)
Order savedOrder = orderRepositoryPort.save(order);

// 3. 调用出站端口(发送通知)
notifyPort.sendNotify(savedOrder.getOrderId());

return savedOrder;
}
}

4. 适配器层(技术实现,全部放在外层)

4.1 入站适配器:HTTP 接口(Controller)

java
package com.order.adapter.inbound;

import com.order.domain.entity.Order;
import com.order.port.inbound.CreateOrderUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/order")
@RequiredArgsConstructor
public classOrderController {

private final CreateOrderUseCase createOrderUseCase;

@PostMapping("/create")
public ResponseEntity<Order> createOrder(@RequestBody Order order) {
return ResponseEntity.ok(createOrderUseCase.createOrder(order));
}
}

4.2 出站适配器:DB 实现(MySQL)

java
package com.order.adapter.outbound;

import com.order.domain.entity.Order;
import com.order.port.outbound.OrderRepositoryPort;
import com.order.infra.mapper.OrderMapper;
import com.order.infra.po.OrderPO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
* DB 适配器:实现端口接口
* 领域层完全不知道DB是什么
*/
@Component
@RequiredArgsConstructor
public class OrderRepositoryAdapter implements OrderRepositoryPort {

private final OrderMapper orderMapper;

@Override
public Order save(Order order) {
// 领域实体 → 持久化对象
OrderPO orderPO = convert(order);
orderMapper.insert(orderPO);
return order;
}

private OrderPO convert(Order order) {
// 省略转换逻辑
OrderPO po = new OrderPO();
po.setOrderId(order.getOrderId());
po.setUserId(order.getUserId());
po.setAmount(order.getAmount());
return po;
}
}

4.3 出站适配器:通知实现

java
package com.order.adapter.outbound;

import com.order.port.outbound.NotifyPort;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
* 通知适配器:可随时替换为短信、邮件、MQ
* 领域/应用层完全无感
*/
@Component
@RequiredArgsConstructor
public class NotifyAdapter implements NotifyPort {
@Override
public void sendNotify(String orderId) {
System.out.println("【适配器】发送订单通知:" + orderId);
}
}

四、核心亮点:六边形架构威力体现

场景 1:切换数据库

你只需要新增一个适配器
OrderRepositoryMongoAdapter

领域层、应用层一行代码都不用改!

场景 2:切换通知方式

短信 → 微信 → MQ
只需要修改NotifyAdapter
业务内核完全不动

场景 3:单元测试极简单

java
@MockBean
private OrderRepositoryPort orderRepositoryPort;

@MockBean
private NotifyPort notifyPort;

不用启动 DB、MQ、Redis,直接测试业务逻辑。

五、架构合规性检查

✅ 领域层:无任何外部依赖
✅ 应用层:只依赖领域与端口
✅ 适配器:全部在最外层
✅ 依赖方向:永远向内
✅ 业务与技术完全解耦

这就是标准六边形架构 + DDD 落地形态。

六、总结

六边形架构不是炫技,它真正解决的是:
业务代码不被技术污染,系统永远可扩展、可替换、可测试。

在实战中只要记住三句话:

  • 领域层写业务,不碰任何技术
  • 端口是抽象,适配器是实现
  • 所有依赖必须向内,绝不外翻

这套代码可以直接用于电商、支付、SAAS、微服务项目。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询