DDD分层架构实战:从理论到落地的关键设计

张开发
2026/4/14 21:29:26 15 分钟阅读

分享文章

DDD分层架构实战:从理论到落地的关键设计
1. DDD分层架构的核心设计理念我第一次接触DDD分层架构是在一个电商系统重构项目中。当时系统已经发展到200万行代码各种业务逻辑像意大利面条一样纠缠在一起每次修改需求都像在走钢丝。这时候团队决定引入DDD分层架构经过半年实践系统终于变得清晰可控。那么这个神奇的架构到底有什么魔力DDD分层架构的本质是业务复杂度治理工具。它通过纵向分层和横向限界上下文将庞大的业务系统拆解为可管理的模块。最经典的版本包含四层用户接口层、应用层、领域层和基础层。这就像建造一栋大楼用户接口层是外立面装修应用层是户型设计领域层是承重结构基础层则是水电管网。与传统三层架构最大的区别在于领域层的独立。我曾见过不少项目把业务逻辑写在Service类里结果这些类最后变成上帝类。而在DDD分层架构中领域层是充血模型每个领域对象都携带自己的行为。比如订单的折扣计算应该放在Order实体里而不是OrderService。2. 领域层的实现细节2.1 聚合根的设计陷阱领域层的核心是聚合根设计这也是最容易踩坑的地方。去年我们团队就发生过一个典型案例商品聚合最初包含了库存信息结果在高并发下单时出现严重的锁竞争。后来通过事件溯源模式将库存拆分为独立聚合性能立即提升8倍。好的聚合设计要遵循三个原则一致性边界一个事务只修改一个聚合小聚合聚合不宜超过10个实体通过ID引用聚合间通过ID而非对象引用实际项目中我常用这个检查清单该聚合是否经常被整体加载修改时是否需要强一致性生命周期管理是否统一2.2 领域服务的正确用法很多开发者容易把领域服务变成杂物间把不好归类的方法都扔进去。其实领域服务应该满足三个条件执行的操作涉及多个实体需要访问外部资源如数据库操作本身是无状态的比如电商中的支付处理服务需要协调订单、支付单、账户等多个实体还要调用第三方支付网关这就是典型的领域服务场景。而像计算订单金额这种单一职责的操作应该放在Order实体内部。3. 应用层的编排艺术3.1 服务组合模式应用层最核心的价值是服务编排。在物流系统中我们设计了这样的订单履约流程public class OrderFulfillmentAppService { public void fulfillOrder(OrderId orderId) { // 1. 获取订单 Order order orderRepository.findById(orderId); // 2. 检查库存 inventoryService.checkStock(order); // 3. 创建运单 Shipping shipping shippingService.createShipping(order); // 4. 更新订单状态 order.markAsFulfilled(shipping.getId()); orderRepository.save(order); // 5. 发送领域事件 eventPublisher.publish(new OrderFulfilledEvent(orderId)); } }这个案例展示了应用层的典型工作模式它不包含具体业务规则只是像指挥家一样协调各个领域对象完成任务。3.2 事务边界控制分布式系统中应用层还要处理棘手的事务问题。我们的经验是尽量使用最终一致性对强一致性需求采用Saga模式每个应用服务方法都是一个事务边界比如支付超时场景我们会拆分为创建待支付订单本地事务发起支付调用第三方定时任务检查支付结果补偿机制4. 基础设施层的解耦技巧4.1 仓储模式的实现仓储接口属于领域层实现则放在基础设施层。这种依赖倒置是DDD的精妙之处。在Spring项目中我们这样实现// 领域层 public interface OrderRepository { Order findById(OrderId id); void save(Order order); } // 基础设施层 Repository public class OrderRepositoryImpl implements OrderRepository { PersistenceContext private EntityManager em; Override public Order findById(OrderId id) { return em.find(Order.class, id); } }特别注意仓储应该以聚合根为单位进行操作避免出现OrderItemRepository这种违反DDD原则的设计。4.2 防腐层实践当需要集成外部系统时一定要建立防腐层。我们在对接物流系统时是这样做的在领域层定义ShippingGateway接口在基础设施层提供RestShippingGateway实现对外部数据模型进行转换适配我们的领域模型这样当物流API变更时只需修改基础设施层的实现领域层代码完全不受影响。5. 分层边界的守护策略5.1 架构守护测试随着项目规模扩大分层架构容易腐化。我们引入了ArchUnit来编写架构测试ArchTest static final ArchRule layer_dependencies_are_respected layeredArchitecture() .layer(Interface).definedBy(..interfaces..) .layer(Application).definedBy(..application..) .layer(Domain).definedBy(..domain..) .layer(Infrastructure).definedBy(..infrastructure..) .whereLayer(Interface).mayNotBeAccessedByAnyLayer() .whereLayer(Application).mayOnlyBeAccessedByLayers(Interface) .whereLayer(Domain).mayOnlyBeAccessedByLayers(Application, Interface);这套测试在CI流程中运行有效防止了架构退化。5.2 包结构设计合理的包结构能强化分层意识。推荐按功能模块划分顶层包再按层级划分子包com └── example └── order ├── application ├── domain │ ├── model │ ├── service │ └── repository └── interfaces ├── web └── rpc这种结构比传统的按层级划分更符合领域驱动设计的理念。6. 从单体到微服务的演进当系统需要拆分为微服务时DDD分层架构展现出独特优势。我们的迁移步骤是通过事件风暴识别限界上下文为每个上下文建立独立的分层架构使用领域事件进行上下文集成逐步将共享内核拆分为独立服务在这个过程中清晰的分层边界使得每个服务都能保持内聚而应用层则成为服务间协调的自然场所。

更多文章