什么是 Spring MVC 三层架构?
2026年02月04日
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
面试官提出这个问题,通常旨在考察以下几点:
- 对经典软件架构思想的理解:不仅仅是想知道三个层的名称,更是想知道你是否理解 “关注点分离”、“高内聚低耦合” 这些核心设计原则,以及它们如何提升代码的可维护性、可测试性和可扩展性。
- 对 Spring MVC 中各层职责的清晰认知:你是否能准确描述每一层(Controller, Service, Dao/Repository)应该做什么、不应该做什么,以及它们之间如何协作。
- 理论与框架实践的结合能力:你是否能将这种普适的架构思想与 Spring MVC(或 Spring Boot)框架的具体组件(如
@Controller,@Service,@Repository)联系起来,并说明框架是如何支持这种分层架构的。 - 辨别常见误区:是否能指出在项目中常见的分层错误,例如业务逻辑侵入 Controller 层、Service 层变成“透传层”等,这能反映出你的实战经验。
核心答案
Spring MVC 三层架构是构建基于 Spring 框架的 Web 应用程序时,一种被广泛采用的、约定俗成的分层设计思想。它将应用程序的职责纵向切分为三个核心层次:
- 表示层/控制层:通常对应 Spring MVC 中的 Controller。它负责接收 HTTP 请求、解析参数、调用业务层处理,并最终封装响应数据(JSON/HTML 等)返回给客户端。
- 业务逻辑层:通常对应 Service。它是应用程序的核心,负责实现具体的业务规则、业务流程、事务管理和领域逻辑。它是连接表示层和数据访问层的桥梁。
- 数据访问层:通常对应 Dao 或 Repository。它负责与数据库、缓存、文件系统等持久化存储进行交互,封装所有数据访问细节,提供简洁的 API 供业务层调用。
其核心协作流程是:请求 -> Controller -> Service -> Dao -> 数据库 -> 返回数据 -> Service(业务处理)-> Controller(封装响应)-> 响应。
深度解析
原理与机制
三层架构的驱动力是 “关注点分离”。每一层都有其高度内聚的职责,层与层之间通过明确定义的接口进行通信,从而降低耦合度。
- 数据流向:请求和数据通常自上而下流动(Controller -> Service -> Dao),而结果自下而上返回。
- 依赖方向:这是一种典型的上层依赖下层的架构。Controller 依赖 Service,Service 依赖 Dao。下层对上层一无所知,这保证了核心业务逻辑和数据访问逻辑的独立性。
- Spring 的支撑:Spring 框架通过 依赖注入 和 注解(如
@Controller,@Service,@Repository)完美地实现了各层组件的创建、管理和装配,使这种分层模式易于实施。
代码示例
以下是一个管理用户的简单示例,展示了各层的典型代码结构:
1. 数据访问层:使用 @Repository 标识。
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Spring Data JPA 会自动实现此方法
Optional<User> findByUsername(String username);
}
2. 业务逻辑层:使用 @Service 标识,并注入 Repository。
@Service
@Transactional // 事务管理通常放在 Service 层
public class UserService {
@Autowired
private UserRepository userRepository;
public UserDTO getUserProfile(String username) {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
// 进行业务逻辑处理,例如计算、验证、组合数据等
return convertToDTO(user);
}
private UserDTO convertToDTO(User user) {
// 转换实体为 DTO
return new UserDTO(user.getId(), user.getUsername(), user.getEmail());
}
}
3. 表示层/控制层:使用 @RestController 标识,并注入 Service。
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{username}/profile")
public ResponseEntity<UserDTO> getProfile(@PathVariable String username) {
UserDTO userProfile = userService.getUserProfile(username);
// Controller 主要做请求/响应的协调,不应包含复杂业务逻辑
return ResponseEntity.ok(userProfile);
}
}
注:
UserDTO是一个数据传输对象,用于在层间传递数据,避免直接暴露领域模型或数据库实体。
对比分析与最佳实践
- 三层架构 vs MVC 模式:
- MVC 是一种表现层的设计模式,主要解决用户界面(View)与数据模型(Model)和用户交互逻辑(Controller)的分离问题。
- 三层架构 是整个应用程序的纵向架构,它涵盖了表现层、业务层和数据层。在 Spring MVC 中,我们常说的 “Controller” 对应 MVC 中的 “C”,而 “Service + Dao” 共同构成了 MVC 中更广义的 “Model”。
- 最佳实践:
- 严守职责边界:Controller 只做路由、参数校验和响应封装;Service 承载核心业务逻辑;Dao 只做数据操作。
- 使用 DTO/VO 进行层间数据传输:避免将数据库实体(如
UserJPA Entity)直接传到 Controller 层或返回给前端,以防止暴露内部字段或引起惰性加载异常。 - 事务管理应在 Service 层:利用 Spring 的
@Transactional在 Service 方法上声明事务,保证业务操作的原子性。 - 避免 “贫血模型”:在复杂业务系统中,警惕 Service 层变得过于庞大。可以考虑引入领域驱动设计,将部分业务逻辑富化到领域实体中。
常见误区
- 在 Controller 中编写业务逻辑:这是最常见的反模式,会导致 Controller 臃肿,业务逻辑无法复用,且难以测试。
- Service 层变成“透传层”:如果 Service 方法只是简单地调用一下 Dao 方法然后返回,那就失去了它存在的价值,需要思考是否业务逻辑缺失或被错误地放置了。
- 层与层之间紧耦合:例如,在 Service 层直接使用 HttpServletRequest 等 Web 相关对象,这使得 Service 无法脱离 Web 环境进行单元测试。
总结
Spring MVC 三层架构是一种通过分层实现关注点分离的经典实践,它利用 Spring 框架的 IOC 和注解支持,由 Controller、Service、Dao 各司其职,共同构建出结构清晰、易于维护和测试的企业级应用。