应用架构
应用架构关注单个应用内部的结构设计,解决代码如何组织、职责如何划分、数据如何流转的问题。应用分层 文件详细介绍了典型 Java 应用的分层结构和领域模型。
提示
应用分层、领域模型、工程结构的应用架构设计
架构风格演进
应用内架构不是只有「分层」一种答案,按复杂度递增:
| 风格 | 核心思想 | 适用规模 | 代表 |
|---|---|---|---|
| 分层架构 | 按技术职责垂直分层 | 中小型 CRUD 系统 | Controller/Service/DAO |
| 端口-适配器(六边形) | 领域在中心,适配器在边缘 | 中大型、领域复杂 | 领域模型 + 入站/出站适配器 |
| 整洁架构 | 依赖向内,外层可替换 | 领域驱动设计落地 | UseCase + Entity + Interface |
| CQRS | 读模型与写模型分离 | 读写比悬殊、性能敏感 | Command + Query 分离 |
关键判断:业务简单用分层,领域复杂用六边形/整洁架构。分层架构的问题是业务逻辑容易泄漏到 Service 层,随着业务复杂化,Service 层会膨胀成「上帝类」。
分层结构
典型 Java 应用分为开放 API 层、Web 层、Service 层、Manager 层、DAO 层。每层职责清晰:开放 API 层封装 Service 接口暴露成 RPC 或 HTTP 接口,Web 层处理访问控制和参数校验,Service 层包含核心业务逻辑,Manager 层处理通用业务和第三方封装,DAO 层负责数据访问。
Manager 层的引入是对 Service 层通用能力的下沉。当 Service 层需要调用多个 DAO、处理缓存方案、封装第三方平台时,这些通用逻辑应该下沉到 Manager 层,避免 Service 层过于臃肿。
领域模型
分层领域模型定义了数据在各层之间的流转方式。DO(Data Object)与数据库表结构一一对应,DTO(Data Transfer Object)用于跨层数据传递,BO(Business Object)封装业务逻辑,Query 封装查询条件,VO(View Object)用于模板渲染。
超过 2 个参数的查询应该封装成 Query 对象,禁止使用 Map 传输。这种约束保证了代码的类型安全和可维护性。
异常处理
各层的异常处理策略不同。DAO 层使用 catch(Exception e) 方式抛出 DAOException,不需要打印日志。Service 层出现异常时必须记录出错日志到磁盘,尽可能带上参数信息。Web 层不应该继续往上抛异常,直接跳转到友好错误页面。开放接口层将异常处理成错误码和错误信息方式返回。
工程结构
标准的工程结构包括 src/main/java 下按分层组织的包结构,src/main/resources 下的 MyBatis 映射文件,以及 src/test/java 下的单元测试。model 包下按 DO、DTO、BO、Query、VO 分目录存放数据模型。
设计原则
应用架构的设计遵循单一职责原则、依赖倒置原则、开闭原则。设计规约 中的强制规则——存储方案评审、UML 建模指导——为应用架构提供了规范约束。错误码设计 是 API 响应格式的重要组成部分,保证错误信息的标准化和可追溯性。
FAQ
Q: 分层架构和 DDD 是什么关系? A: 分层架构按「技术职责」分层(Controller/Service/DAO),DDD 按「业务领域」划分模块并强调领域模型。两者不冲突:DDD 的落地通常采用「四层架构」——接口层(API)→ 应用层(Application Service)→ 领域层(Entity/Value Object/聚合)→ 基础设施层(Repository)。本质区别是业务逻辑放哪里:分层架构放 Service,DDD 放在领域层。
Q: 什么时候从分层架构演进到六边形架构? A: 出现以下信号时考虑:1) Service 层超过 500 行或职责明显混乱;2) 需要替换外部依赖(数据库、第三方 API)但改动面大;3) 领域规则复杂,需要单元测试隔离基础设施。演进方式是渐进式的:先把纯领域逻辑抽到独立的 domain 包,再为外部依赖定义接口(端口),最后替换为适配器实现。