Spring MVC 核心流程深度解析:从请求到响应的完美掌控
Spring MVC 是 Spring 框架中处理 Web 请求的核心模块,基于 Model-View-Controller (MVC) 设计模式。它以 DispatcherServlet 为入口,实现从 HTTP 请求到响应的完整生命周期管理。下面从最实用的角度(基于 Spring Boot 2.x/3.x 和 Spring MVC 5.x/6.x)来深度剖析其核心流程,帮助你建立清晰的思维框架。
目标:看完后,你能自信地说“我能掌控 Spring MVC 的请求响应全链路”,并能调试/优化 90% 的 Web 项目问题。
第一步:核心理念与整体架构(先建立大局观)
Spring MVC 的本质是一个前端控制器(Front Controller)模式:
- DispatcherServlet 是总入口,负责分发所有请求。
- 流程像一个“流水线”:请求进来 → 匹配处理器 → 执行逻辑 → 渲染视图 → 返回响应。
- 关键原则:松耦合、可扩展(通过接口/注解自定义组件)。
整体流程图(文本简化版):
HTTP Request → DispatcherServlet (入口)
↓
HandlerMapping (匹配 Controller/Method)
↓
HandlerInterceptor (前置拦截)
↓
HandlerAdapter (执行 Handler)
↓
ModelAndView / ResponseBody (处理结果)
↓
ViewResolver (视图解析)
↓
HandlerInterceptor (后置/完成拦截)
↓
HTTP Response
异常处理:任何步骤出错 → HandlerExceptionResolver → 统一响应。
第二步:核心组件速览(嵌入式/企业级最常用)
| 组件名称 | 作用 | 默认实现/注解支持 | 扩展点 |
|---|---|---|---|
| DispatcherServlet | 总调度器,初始化所有组件 | Spring Boot 自动配置 | web.xml 或 ServletRegistrationBean |
| HandlerMapping | 映射请求到 Handler (Controller 方法) | RequestMappingHandlerMapping (@RequestMapping) | 自定义 Mapping |
| HandlerAdapter | 执行 Handler,返回 ModelAndView | RequestMappingHandlerAdapter (@ControllerAdvice) | 支持 REST/注解 |
| ViewResolver | 解析视图名到实际 View | InternalResourceViewResolver (JSP/Thymeleaf) | 多视图支持 |
| HandlerInterceptor | 拦截器(AOP 式钩子) | — (@Interceptor 或实现接口) | 权限/日志 |
| HandlerExceptionResolver | 异常处理器 | DefaultHandlerExceptionResolver (@ExceptionHandler) | 全局异常 |
| MultipartResolver | 文件上传解析 | StandardServletMultipartResolver | — |
提示:在 Spring Boot 中,这些组件大多自动装配,但你可以用 @Bean 自定义。
第三步:从请求到响应的详细流程拆解(步步追踪)
假设一个典型请求:GET /user/1(注解式 Controller)。
- 请求进入 DispatcherServlet:
- Tomcat/Nettys 等容器转发请求到 DispatcherServlet 的
doService()方法。 - 初始化:Servlet 初始化时加载 Spring 上下文(WebApplicationContext),注册所有组件。
- 代码追踪:
FrameworkServlet.doGet() → DispatcherServlet.doDispatch()(核心分发方法)。
- HandlerMapping 匹配 Handler:
- 遍历所有 HandlerMapping(如 RequestMappingHandlerMapping),根据 URL、Method、Header 等匹配
@RequestMapping方法。 - 返回 HandlerExecutionChain(包含 Handler + Interceptors)。
- 示例:
@GetMapping("/user/{id}") public User getUser(@PathVariable Long id) { ... } - 坑:多 Mapping 时,按顺序匹配(可自定义顺序)。
- 应用前置拦截器 (preHandle):
- 执行链中所有 Interceptor 的 preHandle():如权限检查、日志。
- 如果返回 false,流程中断(直接响应)。
- HandlerAdapter 执行 Handler:
- Adapter(如 RequestMappingHandlerAdapter)调用 Controller 方法。
- 参数解析:@PathVariable、@RequestParam、@RequestBody 等(通过 ArgumentResolvers)。
- 返回值:ModelAndView(视图+模型)或 @ResponseBody(JSON 等)。
- 代码示例:
java @Controller public class UserController { @GetMapping("/user/{id}") public ModelAndView getUser(@PathVariable Long id) { User user = userService.findById(id); // 业务逻辑 ModelAndView mav = new ModelAndView("userDetail"); // 视图名 mav.addObject("user", user); // 模型数据 return mav; } }
或 REST 式:java @RestController public class UserController { @GetMapping("/user/{id}") public User getUser(@PathVariable Long id) { return userService.findById(id); // 自动转 JSON } }
- 处理返回结果:
- 如果是 ModelAndView:收集模型数据。
- 如果是 @ResponseBody:用 HttpMessageConverters(如 MappingJackson2HttpMessageConverter)转 JSON/XML。
- ViewResolver 解析视图:
- 根据视图名(如 “userDetail”)解析成 View(如 JSP、Thymeleaf)。
- 示例配置(application.yml):
yaml spring: thymeleaf: prefix: classpath:/templates/ suffix: .html - 渲染:View.render() 合并模型数据生成 HTML。
- 应用后置/完成拦截器 (postHandle / afterCompletion):
- postHandle:视图渲染前(如修改模型)。
- afterCompletion:响应后(如清理资源),无论成功/失败都执行。
- 返回响应:
- DispatcherServlet 写回 HttpServletResponse(状态码、Header、Body)。
- 结束:请求响应完成。
异常分支:任何步骤抛异常 → HandlerExceptionResolver(如 @ExceptionHandler 方法)处理 → 返回错误视图/JSON。
第四步:真实代码示例(Spring Boot 风格,强烈建议敲一遍)
最小项目结构:
- pom.xml:spring-boot-starter-web
- Application.java:@SpringBootApplication
Controller 示例(见上)。
自定义拦截器(日志示例):
@Component
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("Request URL: {}", request.getRequestURL());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
log.info("Response Status: {}", response.getStatus());
}
}
注册:@Configuration 类中 addInterceptors()。
全局异常处理:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception ex) {
ModelAndView mav = new ModelAndView("error");
mav.addObject("message", ex.getMessage());
return mav;
}
}
第五步:最容易踩的 8 个坑与优化(企业级经验)
- 性能瓶颈:DispatcherServlet 是单线程入口,用线程池/异步 (@EnableAsync) 优化。
- 参数绑定失败:自定义 Converter/Formatter。
- CORS/安全性:用 @CrossOrigin 或 WebSecurityConfigurer。
- 视图解析冲突:多 ViewResolver 时,按优先级。
- 文件上传大小限:multipart.max-file-size 配置。
- REST vs MVC:@RestController = @Controller + @ResponseBody。
- 测试:用 MockMvc 测试全流程(@WebMvcTest)。
- 版本差异:Spring 6.x 支持 Jakarta EE(Servlet 5.0+),迁移时注意包名。
第六步:快速自测清单(验证掌握度)
- DispatcherServlet 的核心方法是什么?(doDispatch)
- HandlerMapping 如何支持注解?(@RequestMapping)
- 返回 String 类型时,ViewResolver 如何工作?(视为视图名)
- 如何处理 JSON 返回?(@ResponseBody + Jackson)
- 拦截器 preHandle 返回 false 会怎样?(中断流程)
- 异常如何统一处理?(@ControllerAdvice + @ExceptionHandler)
- 文件上传用什么组件?(MultipartResolver)
- 如何异步处理请求?(Callable / DeferredResult)
答案自己验证(可查 Spring 官方文档)。如果你把流程图画一遍、代码跑通,恭喜——Spring MVC 核心你已掌控。
有哪部分模糊(如异步 Servlet、WebFlux 对比、源码调试、性能调优)?直接告诉我,我再针对性展开。