
1. DDD项目分层结构核心解析十年前我第一次接触DDD时被各种分层架构图绕得头晕眼花。直到真正在电商中台项目中实践后才发现合理的分层结构对领域驱动设计而言就像建筑的地基之于摩天大楼。下面分享我在多个百万级用户系统中验证过的分层方案以及那些官方文档不会告诉你的实战细节。典型的DDD分层结构包含四个核心层级用户接口层Interface、应用层Application、领域层Domain和基础设施层Infrastructure。这种垂直切割方式与传统的三层架构本质区别在于——它是以领域模型为绝对核心的辐射状结构。就像六边形架构展示的那样所有其他层都围绕着领域层提供服务。关键认知分层不是目的而是手段最终目标是让领域模型能够不受技术细节污染地持续演进。我在金融项目中就曾因初期分层不当导致核心风控模型与ORM框架强耦合后期重构代价惨重。2. 各层职责与交互规范2.1 用户接口层设计要点别看这层在最外围它的设计质量直接影响整个系统的扩展性。在微服务场景下我通常这样组织包结构- interfaces ├── rest # RESTful接口 ├── rpc # Dubbo/gRPC接口 ├── mq # 消息消费者 ├── task # 定时任务入口 └── dto # 数据传输对象避坑指南严禁在Controller中写业务逻辑血泪教训曾因校验逻辑下沉不够导致相同规则在多个接口重复实现DTO转换推荐使用MapStruct比BeanUtils性能高30%以上对于高频接口建议直接在接口层做缓存但要注意与领域层缓存的一致性2.2 应用层的协作模式这是最容易被误解的一层。应用服务Application Service应该像交响乐指挥家——它不演奏具体乐器领域逻辑而是协调各个乐手领域对象完成演出。标准的应用服务方法通常遵循以下模式Transactional public void placeOrder(OrderCommand command) { // 1. 获取聚合根 Order order orderRepository.findById(command.getOrderId()); // 2. 调用领域能力 order.confirmPayment(command.getPayment()); // 3. 发布领域事件 domainEventPublisher.publish(new OrderConfirmedEvent(order)); }性能优化点应用层事务建议控制在3个以内聚合根操作批量操作时考虑使用Command模式合并请求事件发布尽量采用异步方式但要注意事务边界3. 领域层的实现艺术3.1 聚合根设计原则聚合根是DDD中最难把握的概念。经过多个项目迭代我总结出三条铁律一个聚合的事务边界就是一致性边界修改多个聚合时要考虑最终一致性聚合间引用通过ID而非对象避免Hibernate的懒加载陷阱聚合大小应该以单次业务操作能完成的修改量为准典型错误示例// 反模式把User和Order作为同一个聚合 class User { private ListOrder orders; }3.2 领域服务的使用场景当某个业务行为不适合放在实体或值对象中时就需要领域服务。判断标准是操作涉及多个聚合根协作需要依赖外部服务如调用风控系统实现核心业务算法代码示范class TransferService { public void transfer(Account source, Account target, Money amount) { source.debit(amount); target.credit(amount); // 记录审计日志等跨聚合操作 } }4. 基础设施层的实现技巧4.1 仓库实现的三种模式根据项目复杂度可以选择简单CRUD直接使用JPA/Hibernate中等复杂度MyBatis 自定义映射高性能场景JDBC Template 手工优化SQL缓存策略建议一级缓存聚合根级别生命周期事务二级缓存查询结果建议使用Redis对于财务等强一致性场景慎用缓存4.2 防腐层设计对接外部系统时一定要建立防腐层ACL。这是我用过的两种有效模式// 模式1适配器防腐层 class ExternalSystemAdapter { private AntiCorruptionLayer acl; public DomainModel getData() { ExternalModel external client.call(); return acl.translate(external); } } // 模式2门面模式 class UnifiedGateway { public UnifiedResult call(UnifiedRequest req) { // 统一处理鉴权、熔断、降级 } }5. 分层实战问题排查5.1 循环依赖问题当出现领域层依赖基础设施层又需要基础设施层实现领域层接口时解决方案是在领域层定义Repository接口在基础设施层实现接口通过依赖注入解决Spring或手动DI5.2 事务管理陷阱分布式事务的推荐方案单服务多数据源Spring JTA跨服务Saga模式补偿事务千万避免XA两阶段提交性能杀手5.3 性能优化记录在最近一个日订单百万级的系统中我们通过以下分层优化将TPS提升了5倍接口层引入GraphQL替代部分REST接口应用层使用CQRS分离读写模型领域层将大聚合拆分为事件溯源的微聚合基础设施用JdbcTemplate替代Hibernate6. 项目结构示例这是经过多个项目验证的标准目录结构src ├── main │ ├── java │ │ └── com │ │ └── company │ │ └── product │ │ ├── interfaces # 用户接口层 │ │ ├── application # 应用层 │ │ ├── domain # 领域层 │ │ │ ├── model # 聚合根/实体 │ │ │ ├── service # 领域服务 │ │ │ └── event # 领域事件 │ │ └── infrastructure # 基础设施层 │ └── resources │ ├── mapper # MyBatis映射文件 │ └── schema # 数据库脚本 └── test └── java └── com └── company └── product ├── interfaces ├── application ├── domain └── infrastructure在微服务架构下每个服务的包名建议采用com.company.[bounded_context].[subdomain]的格式。比如电商系统的支付子域com.company.ecommerce.payment7. 测试策略建议7.1 分层测试重点接口层MockMVC测试API契约应用层验证事务边界和领域对象调用领域层单元测试覆盖所有业务规则基础设施集成测试验证数据库操作7.2 测试数据准备推荐使用Testcontainers而不是H2Testcontainers class RepositoryTest { Container static PostgreSQLContainer? postgres new PostgreSQLContainer(); BeforeAll static void setup() { // 配置数据源 } }8. 演进式架构实践领域模型不是一成不变的。我们在物流系统中就经历了三次重大调整初期简单的订单-运单模型中期引入运输计划聚合根后期拆分为路由引擎和运力调度两个限界上下文每次调整时清晰的分层结构让我们能够保持接口层稳定修改领域层不影响API逐步替换基础设施实现如从JPA切换到NoSQL通过领域事件保持新旧模型兼容最后分享一个实用技巧在IDE中为不同层设置不同颜色标签可以直观发现违规的跨层引用。这是我用IntelliJ的层可视化配置layer nameDomain color0xE6E6FA package prefixcom.company.*.domain.*/ /layer