应用分层
应用分层是软件架构的基础,合理的分层能够提高代码的组织性、可维护性和可扩展性。
提示
应用分层架构规范,包括典型Java应用分层结构
分层结构
典型 Java 应用分为以下几层:
各层职责
开放 API 层
封装 Service 接口暴露成 RPC 接口,或通过 Web 封装成 HTTP 接口,也可由网关控制层处理。
终端显示层
各个端的模板渲染并执行显示的层,包括:
- Velocity 渲染
- JS 渲染
- JSP 渲染
- 移动端展示
Web 层
主要职责:
- 访问控制转发
- 基本参数校验
- 不复用的业务简单处理
Service 层
相对具体的业务逻辑服务层,包含核心业务规则和流程。
Manager 层
通用业务处理层,具有以下特征:
- 对第三方平台封装的层,预处理返回结果及转化异常信息
- 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理
- 与 DAO 层交互,对多个 DAO 的组合复用
DAO 层
数据访问层,与底层数据存储交互:
- MySQL / Oracle
- HBase / OB
- 其他数据存储服务
第三方服务
包括:
- 其它部门 RPC 服务接口
- 基础平台
- 其它公司的 HTTP 接口(淘宝开放平台、支付宝付款服务、高德地图服务等)
外部数据接口
外部应用数据存储服务提供的接口,多见于数据迁移场景。
分层领域模型
DO (Data Object)
与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
DTO (Data Transfer Object)
Service 或 Manager 向外传输的对象,用于跨层数据传递。
BO (Business Object)
业务对象,由 Service 层输出的封装业务逻辑的对象。
Query
数据查询对象,各层接收上层的查询请求。超过 2 个参数的查询封装,禁止使用 Map 类传输。
VO (View Object)
显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
分层异常处理
DAO 层
产生的异常类型多,无法用细粒度异常 catch。使用 catch(Exception e) 方式,抛出 DAOException,不需要打印日志。
Service 层
出现异常时必须记录出错日志到磁盘,尽可能带上参数信息,保护案发现场。
Manager 层
与 Service 同机部署时,日志方式与 DAO 层处理一致;单独部署时采用与 Service 一致的方式。
Web 层
处于顶层,不应该继续往上抛异常。意识到异常将导致页面无法正常渲染时,直接跳转到友好错误页面,加上友好的错误提示信息。
开放接口层
将异常处理成错误码和错误信息方式返回。
依赖原则
默认上层依赖于下层,箭头关系表示可直接依赖:
- 开放 API 层可以依赖于 Web 层(Controller 层)
- 开放 API 层也可以直接依赖于 Service 层
- 其它层遵循同样的依赖规则
工程结构示例
src/
├── main/
│ ├── java/
│ │ └── com/example/
│ │ ├── openapi/ # 开放 API 层
│ │ ├── web/ # Web 层(Controller)
│ │ ├── service/ # Service 层
│ │ ├── manager/ # Manager 层
│ │ ├── dao/ # DAO 层
│ │ └── model/ # 数据模型
│ │ ├── do/ # DO
│ │ ├── dto/ # DTO
│ │ ├── bo/ # BO
│ │ ├── query/ # Query
│ │ └── vo/ # VO
│ └── resources/
│ └── mapper/ # MyBatis 映射文件
└── test/
└── java/ # 单元测试适用场景
| 场景 | 分层策略 | 说明 |
|---|---|---|
| 中大型 Java Web 项目 | 完整五层(OpenAPI/Web/Service/Manager/DAO) | 职责清晰,便于团队协作 |
| 小型项目 | 简化三层(Controller/Service/DAO) | 减少层间转换开销 |
| 对外开放 API | 独立 OpenAPI 层 | 与内部接口隔离,便于版本管理 |
| 多数据源场景 | Manager 层封装数据源切换 | 对 Service 层屏蔽数据源差异 |
FAQ
Q: Manager 层和 Service 层的区别是什么? A: Service 层处理核心业务逻辑,Manager 层处理通用业务能力。当 Service 层需要调用多个 DAO、处理缓存方案、封装第三方平台时,这些通用逻辑应该下沉到 Manager 层。Manager 层是 Service 层的"工具箱"。
Q: 为什么不能跨层调用? A: 默认上层依赖下层,跨层调用会破坏分层的隔离性。但开放 API 层可以同时依赖 Web 层和 Service 层,这是为了减少不必要的层间转换。关键是依赖方向只能向下,不能反向。
Q: DO、DTO、BO、VO 什么时候转换? A: DO 在 DAO 层产出,DTO 在 Service/Manager 层之间传递,BO 封装业务逻辑结果,VO 在 Web 层渲染。转换发生在层间交界处:DAO 返回 DO,Service 将 DO 转为 DTO 输出,Controller 将 DTO 转为 VO 返回。