Spring MVC 全流程详解:从请求到响应的完整链路
Spring MVC 作为分层架构的 Web 框架,其核心价值在于通过前端控制器(DispatcherServlet) 统一调度所有组件,将 HTTP 请求转化为业务逻辑处理与响应生成的标准化流程。从 “请求接收→组件协作→响应返回” 三个阶段,拆解 Spring MVC 的全流程执行逻辑,并结合核心组件(如 HandlerMapping、HandlerAdapter、ViewResolver)的作用,让你彻底理解每一步的底层原理。
Spring MVC 核心组件回顾
在解析全流程前,先明确参与流程的核心组件及其职责,这是理解流程的基础:
| 组件名称 | 核心职责 |
|---|---|
| DispatcherServlet | 前端控制器,全流程的 “总指挥”:接收请求、调度其他组件、返回响应 |
| HandlerMapping | 处理器映射器:根据请求 URL 找到对应的 Handler(Controller 方法)及拦截器,封装为 HandlerExecutionChain |
| HandlerAdapter | 处理器适配器:适配不同类型的 Handler,调用其业务逻辑(如反射调用 @RequestMapping 方法) |
| Handler(Controller) | 业务处理器:执行具体的业务逻辑,返回 ModelAndView(模型数据 + 视图名)或直接返回 JSON |
| HandlerInterceptor | 拦截器:在请求处理的不同阶段(preHandle/postHandle/afterCompletion)执行横切逻辑(如权限校验、日志记录) |
| ViewResolver | 视图解析器:将逻辑视图名(如 “user/list”)解析为具体的 View 对象(如 JSP、FreeMarker 模板) |
| View | 视图:渲染模型数据到视图模板,生成 HTML 响应(如 JSP 引擎解析 EL 表达式) |
| HandlerMethodArgumentResolver | 参数解析器:将 HTTP 请求数据(URL 参数、请求体、请求头)绑定为 Controller 方法参数 |
| HttpMessageConverter | 消息转换器:处理请求体 / 响应体与 Java 对象的转换(如 JSON 与 User 对象互转) |
Spring MVC 全流程拆解(11 个核心步骤)
以下流程以 “用户访问 http://localhost:8080/user/list 获取用户列表” 为例,结合组件协作详细解析每一步:
阶段 1:请求接收(客户端→DispatcherServlet)
步骤 1:客户端发送 HTTP 请求
用户通过浏览器 / Postman 发送 GET 请求 http://localhost:8080/user/list,请求经 Web 容器(如 Tomcat)接收后,根据 web.xml 中 DispatcherServlet 的映射规则(<url-pattern>/</url-pattern>),将请求转发给 DispatcherServlet。
步骤 2:DispatcherServlet 初始化检查
若 DispatcherServlet 未初始化(首次请求),会触发其初始化流程:
- 调用
HttpServlet的init()方法,通过继承链(DispatcherServlet→FrameworkServlet→HttpServletBean)完成上下文创建; - 初始化核心策略组件(HandlerMapping、HandlerAdapter、ViewResolver 等),默认从
DispatcherServlet.properties加载实现类,或使用mvc:annotation-driven自动注册的组件。
阶段 2:请求调度(DispatcherServlet→组件协作)
步骤 3:DispatcherServlet 调用 HandlerMapping 查找 Handler
DispatcherServlet 调用 getHandler(request) 方法,遍历所有 HandlerMapping(如 RequestMappingHandlerMapping),根据请求 URL 匹配对应的 HandlerExecutionChain(包含 Handler 和拦截器):
- 匹配逻辑:
RequestMappingHandlerMapping解析@Controller类中@RequestMapping("/user/list")注解,找到对应的HandlerMethod(封装UserController.list()方法); - 拦截器整合:将与当前 URL 匹配的拦截器(如
LoginInterceptor)加入HandlerExecutionChain,形成 “拦截器 1→拦截器 2→Handler” 的执行链。
核心源码(DispatcherServlet):
1 | HandlerExecutionChain mappedHandler = getHandler(processedRequest); |
步骤 4:DispatcherServlet 调用 HandlerAdapter 适配 Handler
DispatcherServlet 调用 getHandlerAdapter(handler) 方法,遍历所有 HandlerAdapter(如 RequestMappingHandlerAdapter),找到支持当前 HandlerMethod 类型的适配器:
- 适配逻辑:
RequestMappingHandlerAdapter的supports()方法判断handler是否为HandlerMethod类型,返回true表示支持; - 作用:解决
DispatcherServlet无法直接调用不同类型 Handler 的问题(如HandlerMethod、Controller接口),通过适配器统一调用逻辑。
核心源码:
1 | HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); |
步骤 5:执行拦截器 preHandle 方法(正序)
DispatcherServlet 调用 mappedHandler.applyPreHandle(request, response),按拦截器配置顺序执行 preHandle 方法:
- 执行逻辑:若拦截器返回
true,继续执行下一个拦截器;若返回false,触发已执行拦截器的afterCompletion方法(反序),并终止流程(如未登录拦截); - 典型场景:权限校验(如检查 Session 中是否有登录用户)、请求日志记录(记录请求 URL、IP)。
核心源码(HandlerExecutionChain):
1 | boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { |
步骤 6:HandlerAdapter 调用 Handler 执行业务逻辑
HandlerAdapter 调用 handle(request, response, handler) 方法,通过反射执行 HandlerMethod 对应的 Controller 方法(UserController.list()),核心逻辑包括:
- 参数解析:
RequestMappingHandlerAdapter调用HandlerMethodArgumentResolver解析方法参数(如@RequestParam、@ModelAttribute),将 HTTP 请求数据绑定为 Java 类型(如Integer page = 1); - 请求体转换:若方法参数标注
@RequestBody,调用HttpMessageConverter(如MappingJackson2HttpMessageConverter)将请求体 JSON 转为 Java 对象; - 业务逻辑执行:反射调用
UserController.list()方法,查询用户列表数据,返回ModelAndView(如new ModelAndView("user/list", "userList", userList))或@ResponseBody标注的 JSON 对象。
核心源码(RequestMappingHandlerAdapter):
1 | ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); |
步骤 7:执行拦截器 postHandle 方法(反序)
若 Handler 执行成功(无异常),DispatcherServlet 调用 mappedHandler.applyPostHandle(request, response, mv),按拦截器配置反序执行 postHandle 方法:
- 典型场景:修改
ModelAndView数据(如统一添加当前登录用户信息)、替换视图(如动态切换主题视图); - 注意:若 Handler 抛出异常,此步骤跳过,直接进入异常处理流程。
核心源码:
1 | void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { |
阶段 3:响应生成(视图渲染 / 异常处理→客户端)
步骤 8:异常处理(若有异常)
若 Handler 或拦截器抛出异常,DispatcherServlet 调用 processHandlerException(request, response, mappedHandler, ex),遍历 HandlerExceptionResolver(如 ExceptionHandlerExceptionResolver)处理异常:
- 异常解析:
ExceptionHandlerExceptionResolver查找@ControllerAdvice或 Controller 内的@ExceptionHandler方法,执行异常处理逻辑(如返回错误 JSON 或错误视图); - 结果生成:若异常处理成功,生成错误
ModelAndView;若失败,直接抛出异常,由 Web 容器返回 500 错误页面。
步骤 9:视图渲染(若无异常且需视图)
若 Handler 返回 ModelAndView(非 @ResponseBody),DispatcherServlet 调用 render(mv, request, response) 完成视图渲染:
- 视图解析:
ViewResolver(如InternalResourceViewResolver)将逻辑视图名(如 “user/list”)解析为物理视图路径(如/WEB-INF/jsp/user/list.jsp),创建View对象(如JstlView); - 模型数据暴露:将
ModelAndView中的模型数据(如userList)存入HttpServletRequest域(request.setAttribute("userList", userList)); - 视图渲染:
View对象调用render()方法,通过 Web 容器(如 Tomcat 的 JSP 引擎)解析视图模板,填充模型数据,生成 HTML 响应。
核心源码(DispatcherServlet):
1 | render(mv, request, response); |
步骤 10:执行拦截器 afterCompletion 方法(反序)
无论 Handler 执行成功或失败,DispatcherServlet 最终调用 mappedHandler.triggerAfterCompletion(request, response, ex),按拦截器配置反序执行 afterCompletion 方法:
- 典型场景:释放资源(如关闭文件流、数据库连接)、记录请求处理耗时、清理 ThreadLocal 变量;
- 注意:仅执行 “
preHandle成功返回true” 的拦截器的afterCompletion方法。
核心源码:
1 | void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { |
步骤 11:DispatcherServlet 返回响应
视图渲染完成后,DispatcherServlet 将 HTML 响应(或 @ResponseBody 生成的 JSON 响应)通过 Web 容器返回给客户端,完成整个请求流程。
全流程示意图
为更直观理解,结合步骤绘制简化流程:
关键注意事项
- 组件优先级:
- 多个 HandlerMapping/HandlerAdapter 按
order属性排序(值越小优先级越高); - 拦截器执行顺序:
preHandle正序,postHandle/afterCompletion反序。
- 多个 HandlerMapping/HandlerAdapter 按
- 前后端分离场景差异:
- 若 Controller 方法标注
@ResponseBody,步骤 9(视图渲染)跳过,直接通过HttpMessageConverter生成 JSON 响应; - 异常处理返回 JSON 而非错误视图,需确保
@ExceptionHandler方法标注@ResponseBody或使用@RestControllerAdvice。
- 若 Controller 方法标注
- 性能优化点:
- 视图缓存:
ViewResolver开启缓存(cache=true),避免重复解析视图路径; - 组件初始化:
load-on-startup=1配置DispatcherServlet,避免首次请求初始化延迟; - 静态资源处理:通过
mvc:resources或default-servlet-handler让 Web 容器直接处理静态资源,避免DispatcherServlet拦截。
- 视图缓存:
总结
Spring MVC 全流程的核心是 “DispatcherServlet 统一调度 + 组件各司其职”,通过分层设计(请求接收→调度→业务执行→响应生成)实现解耦,让每个组件专注于单一职责:
- 前端控制器(DispatcherServlet):总指挥,协调所有组件;
- 映射器 / 适配器:连接请求与 Handler,解决适配问题;
- 拦截器:横切关注点处理,不侵入业务代码;
- 视图解析器:专注视图渲染,支持多种模板技术
v1.3.10