分层架构(DAO/Mapper/Repository/Service/Controller/Manager)
一、体系总览
1.1 整体分层链路与上下游关系
这套组件是Java企业级开发(Spring生态为主)中,实现分层架构、职责解耦、代码复用的核心功能单元,完整的标准请求链路为:客户端请求 → Controller → Service → Manager → Repository/DAO/Mapper → 数据库/第三方服务
各组件按职责分为4个核心层级,从上到下依赖关系单向传递,禁止反向依赖与跨层调用:
| 层级分类 | 包含组件 | 核心定位 |
|---|---|---|
| 入口层 | Controller | 系统对外门面,请求流量的入口与出口 |
| 业务层 | Service、Manager | 业务逻辑的核心承载,Service负责流程编排,Manager负责通用原子能力复用 |
| 数据访问抽象层 | Repository、DAO | 业务与数据存储的解耦层,Repository面向领域模型,DAO面向数据库表 |
| 数据访问实现层 | Mapper | ORM框架对数据访问的具体实现,直接与数据库交互 |
1.2 贯穿全体系的核心设计原则
- 单一职责原则(SRP):每个组件仅负责一类固定职责,边界清晰,避免万能类
- 依赖倒置原则(DIP):上层仅依赖抽象接口,不依赖底层具体实现,实现解耦
- 开闭原则(OCP):对扩展开放,对修改关闭,通过接口抽象适配变化
- 迪米特法则:组件仅与直接相邻的组件交互,禁止跨层调用
- 关注点分离:业务逻辑、数据访问、请求处理、通用技术能力彻底分离,降低系统复杂度
二、各组件深度结构化拆解
2.1 Controller 层:请求入口与流量网关
核心定义:MVC架构中的控制器,是HTTP/RPC请求的系统对外门面,负责请求的接收、校验、路由与结果封装,是客户端与系统内部的唯一交互入口。
核心职责
- 请求接收与路由:匹配HTTP方法与URL路径,接收路径变量、请求体、查询参数等
- 基础参数校验:完成非空、格式、长度、范围等无业务属性的参数合法性校验(JSR-380规范)
- 协议转换:将请求参数转换为业务层所需的DTO对象,将业务结果封装为统一响应体
- 流量与安全前置:完成鉴权、限流、黑白名单等前置校验,兜底异常处理
- 特殊请求处理:支持异步请求、文件上传下载、WebSocket等场景
设计原则与规范
- 瘦Controller原则:绝对不包含业务逻辑,仅做请求转发与结果封装
- 无状态原则:单例无状态,禁止定义可变成员变量
- 统一响应原则:所有接口返回统一格式的响应体,异常统一封装转换
典型实现与误区
- 典型实现:Spring MVC的
@RestController/@Controller注解 - 高频误区:在Controller中编写业务逻辑、直接调用DAO/Mapper跨层访问、参数校验缺失、原始异常直接抛出
边界关系
- 上游:客户端(浏览器、APP、第三方服务)
- 下游:仅依赖Service层接口,禁止依赖更下层组件
2.2 Service 层:核心业务逻辑编排层
核心定义:系统业务能力的核心载体,是连接入口层与数据访问层的桥梁,负责核心业务规则实现、业务流程编排与事务控制。
核心职责
- 核心业务规则实现:封装业务领域的核心规则与校验(如“下单时余额需大于订单金额”)
- 业务流程编排:按业务场景编排多个原子操作的执行顺序(如下单全流程)
- 事务管理:定义事务边界,保证多数据操作的原子性(Spring
@Transactional) - 依赖调度:调用Manager层通用能力、Repository/DAO层数据访问能力完成业务
- 业务异常处理:抛出业务规则校验异常,由Controller层统一封装返回
设计原则与规范
- 厚Service薄Controller原则:核心业务逻辑必须下沉到Service层
- 单一职责:一个Service类仅负责一个业务领域,避免万能Service
- 面向接口编程:必须定义接口,上层仅依赖接口,不依赖实现类
- 无状态原则:单例无状态,禁止定义可变成员变量
典型实现与误区
- 典型实现:Spring
@Service注解,采用接口+实现类模式 - 高频误区:Service类代码臃肿、包含基础参数校验、直接操作数据库/第三方接口、事务控制不当(大事务、事务失效)、重复代码未下沉复用
边界关系
- 上游:仅被Controller层依赖,禁止反向依赖Controller
- 下游:依赖同领域其他Service接口、Manager层接口、Repository/DAO层接口
2.3 Manager 层:通用原子能力封装层
核心定义:Service层的“原子能力工具箱”,位于Service层之下、数据访问层之上,用于解决多Service通用逻辑复用、第三方系统交互隔离、复杂数据操作封装等问题,中小项目可省略,中大型/微服务项目强烈建议引入。
核心职责
- 通用逻辑复用:封装多Service共用的原子逻辑(如缓存操作、分布式锁、幂等处理、通用数据查询)
- 外部依赖隔离:封装第三方系统/中间件调用(支付网关、短信服务、Redis、MQ、RPC调用),屏蔽底层实现变化
- 复杂数据操作封装:封装跨多Mapper的复杂查询、批量操作、数据聚合,避免Service层直接操作多Mapper
- 技术能力兜底:统一实现重试、熔断降级、容错、日志埋点等非业务技术代码
设计原则与规范
- 原子性原则:方法仅做一件事,无业务流程编排,业务编排必须在Service层
- 通用性原则:仅被单个Service使用的逻辑禁止放入Manager层
- 无事务原则:不控制事务边界,仅被Service层的事务包含
- 隔离性原则:对上层屏蔽底层技术细节,实现依赖解耦
典型实现与误区
- 典型实现:Spring
@Component注解,如UserManager、CacheManager、SmsManager - 高频误区:与Service职责混淆、在Manager中编写业务流程、反向依赖Service、与Mapper职责重叠、控制事务
边界关系
- 上游:仅被Service层依赖,禁止被Controller直接调用
- 下游:依赖DAO/Mapper/Repository、第三方系统、中间件
2.4 Repository 层:DDD领域驱动仓储层
核心定义:DDD(领域驱动设计)的核心组件,是面向领域聚合根的对象集合管理抽象,以“集合”的语义管理聚合根生命周期,彻底屏蔽底层存储细节,实现领域模型与数据存储的解耦。
核心职责
- 聚合根生命周期管理:仅负责聚合根的新增、修改、删除、查询,保证聚合根的完整性与不变性
- 对象映射转换:实现领域对象(DO)与持久化对象(PO)的双向转换,隔离领域模型与数据库表结构
- 存储细节屏蔽:对领域层完全屏蔽底层存储实现(MySQL、Redis、MongoDB等)
- 集合语义封装:接口设计采用
add()、remove()、getById()等集合操作语义,而非数据库CRUD语义 - 领域规则保障:保证聚合根的业务不变量在持久化/查询时不被破坏
设计原则与规范
- 聚合根原则:一个Repository仅对应一个聚合根,聚合内部实体禁止独立创建Repository
- 依赖倒置:Repository接口放在领域层,实现类放在基础设施层,领域层仅依赖接口
- 无业务逻辑原则:禁止在Repository中编写业务规则,业务逻辑必须在领域层实现
典型实现与误区
- 典型实现:Spring Data JPA Repository接口,DDD架构中接口位于domain层,实现位于infrastructure层
- 高频误区:把Repository当成DAO使用、接口设计面向数据库CRUD、给非聚合根创建Repository、领域层依赖实现类、直接暴露PO对象给领域层
边界关系
- 上游:被领域层的领域服务、应用服务(对应传统Service)依赖
- 下游:依赖底层DAO/Mapper、ORM框架、数据库,屏蔽存储细节
2.5 DAO 层:传统数据访问对象层
核心定义:传统三层架构中数据访问层的经典抽象,是Data Access Object(数据访问对象)设计模式的落地,用于封装数据库操作,隔离业务层与数据存储层。
核心职责
- 数据库操作封装:封装单表的CRUD操作,一个DAO对应一张数据库表
- 数据访问细节隔离:屏蔽JDBC连接、SQL执行、结果集处理、异常转换等底层细节
- SQL与代码分离:管理SQL语句,将SQL与Java业务代码解耦
- 结果集映射:将数据库结果集转换为PO对象,反之亦然
- 异常转换:将底层SQLException转换为统一的数据访问异常,屏蔽数据库厂商差异
设计原则与规范
- 单表原则:一个DAO仅对应一张表,禁止多表操作
- 无业务逻辑原则:仅做数据访问操作,绝对不包含业务逻辑
- 面向接口编程:定义DAO接口,业务层依赖接口,不依赖实现类
典型实现与误区
- 典型实现:基于JDBC、Spring JdbcTemplate的DAO模式,Hibernate DAO实现
- 高频误区:在DAO中编写业务逻辑、一个DAO操作多张表、业务层直接写SQL跳过DAO层
边界关系
- 上游:被Service/Manager层依赖,禁止反向依赖上层
- 下游:直接操作数据库,基于JDBC/数据库连接池实现
2.6 Mapper 层:ORM映射数据访问实现层
核心定义:以MyBatis为代表的ORM框架对DAO模式的现代化、轻量化实现,是DAO层的主流落地形态,通过注解/XML配置SQL与Java方法的映射,自动处理参数绑定与结果集映射,消除传统DAO的重复模板代码。
核心职责
- SQL映射:通过接口方法+XML/注解,映射对应的SQL语句,实现数据库CRUD
- 自动参数绑定:自动将方法参数绑定到SQL占位符,处理类型转换
- 结果集自动映射:自动将查询结果映射为PO对象,支持一对一、一对多等复杂映射
- 动态SQL管理:提供动态SQL能力,简化复杂条件查询的编写
- 缓存管理:提供一级/二级缓存,优化查询性能
设计原则与规范
- 单表原则:一个Mapper接口对应一张数据库表
- 无业务逻辑原则:仅做数据访问,禁止包含业务逻辑
- SQL与代码分离:复杂SQL建议写在XML文件中,与Java接口分离
- 细粒度原则:方法粒度要细,避免一个方法对应超级复杂SQL,降低复用性
典型实现与误区
- 典型实现:MyBatis
@Mapper注解,Mapper接口+XML映射文件,MyBatis-PlusBaseMapper - 高频误区:编写复杂多表关联SQL导致维护困难、在Mapper中处理业务逻辑、滥用嵌套映射引发N+1查询问题、跨层调用跳过Mapper直接执行SQL
边界关系
- 上游:被DAO实现类、Manager、Service层依赖
- 下游:基于ORM框架封装JDBC,直接操作数据库
三、核心易混淆组件横向对比
3.1 DAO vs Mapper vs Repository 深度对比
| 对比维度 | DAO(数据访问对象) | Mapper(ORM映射) | Repository(DDD仓储) |
|---|---|---|---|
| 架构定位 | 传统三层架构的数据访问抽象 | DAO模式的ORM具体实现 | DDD架构的领域存储抽象 |
| 设计思想 | 面向数据库表,封装单表CRUD | 面向SQL映射,简化JDBC模板代码 | 面向领域聚合根,模拟集合语义 |
| 操作对象 | 数据库表对应的PO对象 | 数据库表对应的PO对象 | 领域层的聚合根DO对象 |
| 接口语义 | 面向数据库:insert、update、delete | 同DAO,轻量化SQL映射 | 面向集合:add、remove、get、find |
| 核心目标 | 隔离业务层与数据库 | 消除DAO模板代码,简化数据访问 | 隔离领域层与存储,实现领域模型解耦 |
| 与业务耦合 | 与业务逻辑解耦,仅关注数据操作 | 与业务逻辑解耦,仅关注SQL映射 | 与领域模型强绑定,与业务语义对齐 |
| 典型场景 | 传统JDBC项目、轻量级项目 | 绝大多数MyBatis/MyBatis-Plus项目 | DDD架构、复杂业务领域项目 |
3.2 Service vs Manager 边界对比
| 对比维度 | Service层 | Manager层 |
|---|---|---|
| 架构定位 | 核心业务逻辑编排层,业务能力核心 | 通用原子能力封装层,Service的工具箱 |
| 核心职责 | 实现业务规则、编排业务流程、控制事务边界 | 封装通用逻辑、第三方调用、中间件操作、复杂数据聚合 |
| 设计原则 | 面向业务场景,一个Service对应一个业务领域 | 面向通用能力,一个Manager对应一类原子能力 |
| 代码特性 | 包含业务流程、多步骤编排、业务规则校验 | 原子性、无业务流程、高复用性、无事务控制 |
| 事务控制 | 事务边界的定义者,负责事务的开启与回滚 | 不控制事务,仅被事务包含,可跨事务复用 |
| 复用性 | 业务场景专属,复用性低 | 通用能力,可被多Service调用,复用性高 |
| 依赖方向 | 依赖Manager、Mapper、同领域其他Service | 仅依赖Mapper、第三方系统、中间件,禁止依赖Service |
| 是否必须 | 分层架构核心必选层 | 非必须,中小项目可省略 |
四、全链路调用流程与架构适配
4.1 标准全链路执行流程
- 客户端发送HTTP请求,经过过滤器/拦截器完成认证、鉴权等前置处理
- 请求路由到Controller层,完成参数校验、协议转换
- Controller调用Service层接口,传入DTO参数
- Service层完成业务规则校验,编排业务流程,控制事务边界
- Service调用Manager层的通用原子能力,完成缓存、第三方调用、复杂数据查询等操作
- Manager/Service调用Mapper/DAO/Repository层,执行数据库操作
- 结果沿原链路逐层返回,最终由Controller封装为统一响应体返回给客户端
4.2 不同架构体系下的组件适配
传统MVC三层架构
- 表现层:Controller
- 业务层:Service
- 数据访问层:DAO/Mapper
- 适配:可省略Manager层,适合轻量级、业务简单的项目
DDD领域驱动四层架构
- 用户接口层:Controller
- 应用层:ApplicationService(对应传统Service,仅做流程编排)
- 领域层:DomainService(核心业务规则)、Repository接口
- 基础设施层:Repository实现类、Mapper、Manager通用能力
- 适配:以Repository为核心数据访问抽象,Mapper作为底层实现,适合复杂业务的中大型项目
微服务分布式架构
- 网关层:统一入口,替代Controller的鉴权、限流能力
- 接口层:Controller(RESTful接口)、RPC API接口
- 业务层:Service(业务编排)、Manager(封装RPC调用、分布式锁、分布式事务等分布式能力)
- 数据访问层:Repository/Mapper(适配分库分表、读写分离)
- 适配:放大Manager层的作用,实现分布式能力的统一封装与复用
五、最佳实践与避坑指南
5.1 业界通用最佳实践
- 严格遵守分层边界:禁止跨层调用,严格遵循单向依赖规则
- 分层校验原则:Controller做基础格式校验,Service做业务规则校验,Mapper层不做校验
- 数据对象隔离:PO仅在数据访问层使用,DTO用于前后端传输,禁止PO直接暴露给前端,通过MapStruct等工具实现对象转换
- 事务精准控制:事务边界仅在Service层定义,事务内禁止RPC调用、缓存操作等非数据库操作,避免大事务
- 代码复用规范:多Service通用逻辑下沉到Manager层,多Manager通用逻辑封装为工具类,禁止复制粘贴重复代码
- 代码行数管控:Controller建议≤300行,Service≤500行,Manager≤300行,Mapper≤200行,避免单类过度臃肿
5.2 高频错误避坑指南
- 分层混乱跨层调用:禁止Controller直接调用Mapper,即使简单CRUD也要经过Service层,便于后续业务扩展
- 职责错位代码臃肿:禁止Controller写业务逻辑、Service写通用技术代码,严格遵循“瘦Controller、厚Service、通用Manager”
- 事务控制失效:避免非public方法加
@Transactional、异常被捕获不抛出、事务内执行非数据库操作等场景 - SQL滥用性能问题:Mapper以单表查询为主,避免过度多表关联与嵌套映射,防止N+1查询问题
- 对象混用安全风险:禁止PO对象直接返回给前端,避免数据库表结构泄露、敏感字段暴露
- Repository与DAO混淆:DDD项目中必须严格遵守Repository的聚合根原则与集合语义,禁止将Repository退化为DAOe