什么是架构?架构的核心就是为软件的核心复杂度提供有效的管理及消减手段。其中软件的复杂度又分为本质复杂度和偶然复杂度。关于复杂度的概念介绍,请看我之前的一篇架构文章。
软件架构到底是什么?架构都要做哪些事情?
本质复杂度就是软件系统映射的业务功能原生的复杂度,也就是业务核心复杂度。本质复杂度无法降低,只能去有效的管理,那么 DDD 领域驱动设计中领域、限界上下文等核心思想就是解决本质复杂度的。
偶然复杂度是指软件业务功能之外的复杂度,包括为了实现业务功能引入的软件工具、语言、构件及软件架构的组织形式等。因此偶然复杂度又分为工具性偶然复杂度和结构性偶然复杂度。偶然复杂度通过更先进的工具和更优的结构组织可以消减,但永远不能完全消除。
其中 DDD 分层架构(4层)设计,就是管理和消减结构性偶然复杂度的。那么引入 DDD 分层架构,就是最优秀的架构模式吗?显然答案是否定的,架构是不断演进的,永远都有更优的分层模式。比如我们常见的六边形架构(端口和适配器架构)、洋葱架构、整洁架构及清晰架构等。本文我们主要将 DDD 四层分层架构到整洁架构的演化。
01 传统的 DDD 分层架构

用户接口层:用户接口层负责向用户显示信息和解释用户指令。这里的用户可能是:用户、程序、自动化测试和批处理脚本等等。
应用层:应用层是很薄的一层,理论上不应该有业务规则或逻辑,主要面向用例和流程相关的操作。但应用层又位于领域层之上,因为领域层包含多个聚合,所以它可以协调多个聚合的服务和领域对象完成服务编排和组合,协作完成业务操作。
领域层:领域层的作用是实现企业核心业务逻辑,通过各种校验手段保证业务的正确性。领域层主要体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。
领域层包含聚合根、实体、值对象、领域服务等领域模型中的领域对象。
领域模型的业务逻辑主要是由实体和领域服务来实现的,其中实体会采用充血模型来实现所有与之相关的业务功能。其次,你要知道,实体和领域对象在实现业务逻辑上不是同级的,当领域中的某些功能,单一实体(或者值对象)不能实现时,领域服务就会出马,它可以组合聚合内的多个实体(或者值对象),实现复杂的业务逻辑。
基础层:基础层是贯穿所有层的,它的作用就是为其它各层提供通用的技术和基础服务,包括第三方工具、驱动、消息中间件、网关、文件、缓存以及数据库等。比较常见的功能是提供数据库持久化。
02 改良四层架构
DDD 分层架构的原则
分层架构的一个重要原则是每层只能与位于其下方的层发生耦合。分层架构根据每层耦合的紧密程度分为两种:
- 严格分层架构:某层只能与位于其直接下方的层发生耦合。
- 松散分层架构:则允许某层与它的任意下方层发生耦合。
传统的 DDD 分层架构,用户接口层、领域层和应用层均可与基础设施层发生耦合,属于松散分层架构。
这种模式在实际复杂项目中是有问题的, 将基础设施层放在最底层存在缺点,比如此时领域层中直接调用了一些技术实现,违背分层架构的基本原则,难以编写测试用例等。
何解?使用 依赖反转设计原则,具体依赖于抽象,而不是抽象依赖于具体。实现各层对基础资源的解耦。低层服务(如基础设施层)应依赖高层组件(比如用户界面层、应用层和领域层)所提供的接口。
依赖反转后的分层方式:基础设施层在最上方,可实现所有其他层中定义的接口。
低层服务(如基础设施层)应依赖高层组件(比如用户接口层、应用层和领域层)所提供接口。高层定义好仓库的接口,基础设施层实现各层定义好的仓库接口。
优化后的 DDD 分层架构模型就属于 严格分层架构,任何层只能对位于其直接下方的层产生依赖。而传统的 DDD 分层架构则属于松散分层架构,它允许某层与其任意下方的层发生依赖。

那我们怎么选呢?综合我的经验,为了服务的可管理,我建议你采用严格分层架构。
在严格分层架构中,领域服务只能被应用服务调用,而应用服务只能被用户接口层调用,服务是逐层对外封装或组合的,依赖关系清晰。而在松散分层架构中,领域服务可以同时被应用层或用户接口层调用,服务的依赖关系比较复杂且难管理,甚至容易使核心业务逻辑外泄。
试想下,如果领域层中的某个服务发生了重大变更,那该 那该如何通知所有调用方同步调整和升级呢?但在严格分层架构中,你只需要逐层通知上层服务就可以了。
那么,采用严格分层架构后,DDD 代码结构如下图所示:

03 六边形架构
2005 年,Alistair Cockburn 提出了端口与适配器架构(Ports & Adapters Architecture),又称六边形架构(Hexagonal Architecture)。

端口(Port)与适配器(Adapter)架构中的相关概念:
工具(Tools):
应用(application)层使用的工具,如 WebServer、CLI、DB、SearchEngine、MQ 等。
端口(Port):
在 application core 层定义的工具交互规范(即规定工具如何使用 application core,或 application core 如何被工具使用的契约);
对应编程语言中的 interface 定义;
端口的实现应符合应用层业务逻辑(不可简单模仿或直接调用底层工具的 API)。
适配器(Adapter):
连接工具(WebServer、CLI、DB、SearchEngine、MQ)与应用核心(application core)的代码单元。
适配器依赖端口(调用端口或实现端口),但 application core 仅依赖端口(不依赖具体适配器)。
主动适配器(Primary / Driving Adapters):
- 组件:
Controller(REST API)、CLI Handler、Message Listener。
- 职责:接收外部输入,参数转换,主动调用应用核心(Application Core),触发应用执行某项活动。严禁包含业务规则。
- 依赖关系:依赖
ServiceInterface(核心层定义的接口)。
流程:Controller(主动适配器) -> 依赖 ServiceInterface(端口) -> 注入 ServiceImpl(端口的具体实现)
被动适配器(Secondary / Driven Adapters):
- 职责:实现核心层定义的“被驱动端口”(如 UserRepository 接口),处理具体技术细节(SQL、网络调用)。被应用核心(Application Core)调用以执行外部动作,实现应用所定义的端口。
- 组件:JpaUserRepositoryImpl、RedisCacheAdapter。
- 依赖关系:依赖核心层接口,核心层不依赖它们。
- 流程:端口 -> 被动适配器实现端口逻辑 -> 包装系统外部工具
示例:RepositoryInterface(端口)-> 被动适配器 MysqlRepositoryImpl 实现该接口 -> 内部调用 MySQL 数据库。
ServiceImpl 是核心业务逻辑的执行者,位于六边形内部(核心层);Controller 是外部入口的转换器,位于六边形外部(适配层)。两者通过核心层定义的接口解耦。
应用核心层(Application Core)
- 组件:ServiceImpl(用例服务)、ServiceInterface(端口接口)、领域实体、领域服务。
- 职责:ServiceImpl 实现业务流程协调,调用下游的“被驱动端口”(如 UserRepository 接口)。
- 关键特征:完全独立于外部框架,可被单元测试直接覆盖,无 Spring/ASP.NET 等框架注解污染(纯 POJO/Plain Class)。
几边形不重要,可以 N 边;重点是 Port & Adapter 思想。关于端口与适配器架构的优势:
- 核心业务逻辑位于最中心(最重要);
- 核心业务仅依赖 Port;
- Adapter 依赖 Port(主动适配器)或为 Port 提供具体实现(被动适配器);
- 核心业务逻辑与实现细节(技术框架、底层存储、工具、传输/通信机制等)严格隔离;
- 保持核心业务逻辑的可重用性与可测试性。
04 洋葱架构
洋葱架构(Onion Architecture)由 Jeffrey Palermo 于 2008 年提出。

洋葱架构(Onion Architecture)构建在端口与适配器架构(又称六边形架构)之上,在端口与适配器架构中仅提及两层:
- 外层——表示传输(通信)机制和基础设施(Infrastructure)
- 内层——业务逻辑(Business Logic)
而洋葱架构在 DDD(领域驱动设计)基础上,将内层(即业务逻辑层,Business Logic)进一步细分,最终形成以下层次:
- Adapters(适配器层)——即六边形架构中的适配器(Adapter)层
- User Interface(用户界面)、Infrastructure(基础设施)、Tests(测试)
- Application Core(应用核心层),即原六边形架构中心的业务逻辑层(Business Logic Layer)
- Application Services(应用服务层)
- Domain Services(领域服务层)
- Domain Model(领域模型层)
且明确界定了依赖方向:
- 外层依赖内层;
- 内层不依赖外层;
- 并且,在不破坏依赖方向的前提下,外层也可直接调用任一内层(不一定是相邻的下一层),例如参考 CQRS 中 Query 的实现方式(Application Services 直接调用 DAO)。
05 整洁架构(Clean Architecture)
2012 年,Robert C. Martin(又名 Uncle Bob)提出了整洁架构(Clean Architecture),该架构将六边形架构(Hexagonal Architecture)与洋葱架构(Onion Architecture)等整合为一种可实际落地的软件架构方案。

与洋葱架构相比,整洁架构的调整如下:
- 将 Application Services 调整为 Use Cases(用例);
- 将 Domain Services 与 Domain Model 合并/统一调整为 Entities(实体)。
整洁架构并未引入突破性的新概念或新模式,但其价值在于:
- 挖掘并重新强调了某些在实践中被忽视的重要概念、规则与模式;
- 澄清了一些实用且关键的概念、规则与模式;
- 为我们提供了如何将各类概念、规则与模式系统性整合的方法,从而形成一套构建复杂应用并保障其可维护性的标准路径。
06 CQRS
CQRS 是“命令查询职责隔离”(Command Query Responsibility Segregation)的缩写。这是一种将读取数据(查询)和写入数据(命令)的操作分开的模式。通过分离这些关注点,CQRS 可提高可扩展性、可维护性和灵活性。在基于 CQRS 的系统中,通常涉及以下组件:
- Command: 代表改变系统数据的操作。命令负责创建、更新或删除数据,需校验业务规则。
- Query: 表示从系统检索数据的操作。查询负责读取数据而不修改数据。
- Command Handler: 处理和执行命令,更改系统状态。
- Query Handler: 通过从系统检索数据并以合适的格式返回数据来处理查询。

CQRS 与事件溯源的协同
- 事件溯源:命令端通过事件序列持久化状态变更,为查询端提供重建历史的可能性。
- 数据同步机制:通过事件总线(如 Kafka)将命令端事件传播到查询端,更新读模型。
CQRS 与事件溯源结合

07 清晰架构(Explicit Architecture)
2017 年,Herberto Graca 在其《软件架构编年史》系列文章中提出了清晰架构(Explicit Architecture),即对 DDD、六边形架构(Hexagonal)、洋葱架构(Onion)、整洁架构(Clean)以及 CQRS 等多种架构思想进行融合后的综合架构方案。

- 最中心的红色多边形 Application Core(应用核心)表示业务逻辑的实现,即 应用核心。
- 红色多边形的边界即表示 端口(Port),即应用核心的入口/出口定义。
- Application Layer(应用层),包括:
- 使用
Repository 查找一个或多个实体;
- 让这些实体执行若干领域逻辑;
- 再次使用
Repository 将这些实体持久化,以有效保存数据变更;
- 触发应用事件(例如:发送邮件、调用第三方 API、发送消息队列消息等)。
- Application Services(应用服务):负责业务用例的编排服务及其接口定义。应用服务的作用通常如下:
- CQRS 命令/查询处理器
- Event Listener(事件监听器)
- Port(端口)定义,例如:ORM 接口
Repository、搜索引擎接口、消息接口等。
- Domain Layer(领域层):该层包含数据与操作数据的逻辑,它们仅与领域自身相关,独立于调用这些逻辑的业务流程;完全独立,对应用层完全无感知。
- Domain Services(领域服务):封装涉及多个实体(相同或不同类型)的领域逻辑,且领域服务之间可相互调用。
- Domain Models(领域模型):位于架构的正中心,完全不依赖外部任何其他层次的领域模型。它涵盖了领域中各类概念性的业务对象,如实体(Entity)、值对象(Value Object)、聚合根(Aggregate Root),以及在领域建模中使用的其他对象(例如领域事件 Domain Events,可简单理解为消息)。
- 红色多边形的外侧左半圆部分即为 主/主动适配器(用户界面 User Interface 实现)
- 例如:Spring MVC 中的
Controller 实现
- Command Query Bus 命令/查询总线
- 红色多边形的外侧右半圆部分即为 次/被动适配器(基础设施 Infrastructure 实现)
- 例如:通过数据持久化实现 MySQL、短信通知、MQ 消息通知、搜索引擎(如 Elasticsearch)等;
- Event Bus(事件总线)
- 依赖方向为 由外向内,且内层对(外部)外层一无所知(参见前文洋葱架构的说明)。
采用 按组件分包(Package By Component) 方式,即整合传统“按层分包(Package By Layer)”与“按特性分包(Package By Feature)”两种策略。其中,“组件(Component)”可理解为:
- 属于特定领域内的业务逻辑服务与数据访问逻辑的组合;
- 或进一步理解为一个具体的业务领域模块,例如账单(Billing)、用户(User)、评论(Comment)、账户(Account)等。
在清晰架构(Explicit Architecture)中,可理解为:
- 首先按 层次 进行分包:
- 表现层(Presentation)
- 业务核心层(Application Core)
- 基础设施层(Infrastructure)
- 然后,在每层次内部,再进一步按 特性(或功能模块)进行分包。
云栈社区的技术文档板块整理了丰富的架构设计白皮书与避坑指南,方便你随时查阅。
→ 技术文档板块