什么是洋葱架构
洋葱架构(Onion Architecture)由 Jeffrey Palermo 在 2008 年提出,以领域模型为中心向外分层:领域实体与值对象在最内层,向外依次是领域服务、应用服务与基础设施。核心约束只有一条——依赖只能指向内层,外层通过实现内层定义的接口来接入数据库、消息与界面。它与六边形、整洁架构在术语与层数上不同,规则实质一致。
基本信息
| 最内层 | 领域实体、值对象与领域规则,不依赖任何框架 |
|---|---|
| 中间层 | 领域服务与应用服务,负责用例编排、事务与授权 |
| 最外层 | 数据库、消息、UI、外部接口的适配器实现 |
| 关键约束 | 依赖向内,接口由内层定义、外层实现(依赖倒置) |
落地要点
- 依赖只向内:外层引用内层,内层不感知外层实现细节
- 接口内定义:仓储与网关接口放在内层,外层写适配器实现
- 编排放中间:事务边界、授权与流程控制写在应用服务里
- 领域层保持纯净:不引入 ORM 注解、HTTP 类型与框架基类
- 跨层传数据:用命令与 DTO 对象,避免持久化实体向外泄漏
- 包结构对映:领域包不依赖应用包与基础设施包,用自动检查守住
各层测试策略
| 层 | 测试方式 | 要点 |
|---|---|---|
| 领域层 | 单元测试 | 不启动框架,直接验证规则 |
| 应用服务 | 集成测试 | 用内存适配器替换数据库 |
| 基础设施 | 契约测试 | 验证适配器满足内层接口 |
| 跨层约束 | 静态检查 | 依赖方向违规即构建失败 |
依赖方向示意
依赖方向示意
# 依赖方向(箭头表示「依赖于」)
应用服务 --> 领域模型与领域服务
基础设施 --> 内层定义的接口(仓储、网关)
领域模型 --> (无外部依赖,仅语言本身的类型)
# 违规示例
领域实体上直接挂 ORM 注解、继承框架基类、引用 HTTP 请求对象
# 检查方式
把依赖方向写成静态分析规则,纳入构建流程,违规即失败判断是否真的分层看签名而非目录:只要内层的方法签名里出现外层类型,分层就已被破坏。
领域层纯净的收益在测试:规则可以在不启动框架、不连数据库的情况下被验证,回归反馈快且稳定。