SpringMVC 的执行过程核心是 “前端控制器(DispatcherServlet)统一调度,各组件分工协作” ,整体流程围绕 “请求接收→处理器匹配→业务执行→视图渲染→响应返回” 展开,以下是详细拆解(含核心组件作用和执行顺序):
一、核心组件铺垫(先明确角色,再看流程)
在理解流程前,先记住 5 个核心组件的职责:
- DispatcherServlet(前端控制器) :SpringMVC 的 “中央调度器”,统一接收请求、分发任务、整合响应,是流程的核心入口和出口。
- HandlerMapping(处理器映射器) :根据请求路径(URL)匹配对应的 处理器(Handler) (如 Controller 的方法),并返回 “处理器执行链”(Handler + 拦截器)。
- HandlerAdapter(处理器适配器) :适配不同类型的 Handler(如注解式 @RequestMapping、XML 配置的 Controller),提供统一的执行接口,避免 DispatcherServlet 直接依赖具体 Handler 实现。
- ViewResolver(视图解析器) :将 Handler 返回的 ModelAndView 中的逻辑视图名(如 "index")解析为具体的物理视图(如
/WEB-INF/views/index.jsp)。 - View(视图) :接收 Model 数据,渲染页面(如 JSP、Thymeleaf),最终生成响应内容。
二、完整执行流程(10 步拆解)
假设用户发送请求:http://localhost:8080/springmvc/user/list(查询用户列表),流程如下:
1. 客户端发送请求,Tomcat 接收并转发
- 用户通过浏览器 / 客户端发送 HTTP 请求(GET/POST 等),请求被 Web 服务器(如 Tomcat)接收。
- Tomcat 根据项目的
web.xml配置(或 SpringBoot 自动配置),发现请求路径匹配DispatcherServlet的映射规则(如/或/springmvc/*),将请求转发给 DispatcherServlet。
2. DispatcherServlet 接收请求,触发流程
DispatcherServlet作为前端控制器,不直接处理业务,而是启动 “调度流程”,首先需要找到 “能处理该请求的处理器(Handler)”。
3. DispatcherServlet 调用 HandlerMapping,匹配 Handler
-
DispatcherServlet调用容器中的HandlerMapping(默认是RequestMappingHandlerMapping,处理注解式@RequestMapping)。 -
HandlerMapping根据请求路径(/user/list)、请求方法(GET)等信息,匹配对应的 Handler—— 即 Controller 中被@RequestMapping("/user/list")注解的方法(如UserController.list())。 -
HandlerMapping返回一个 HandlerExecutionChain(处理器执行链) ,包含两部分:- 目标 Handler:
UserController.list()方法; - 拦截器(Interceptor):项目中配置的全局拦截器或局部拦截器(如登录校验拦截器)。
- 目标 Handler:
4. DispatcherServlet 调用 HandlerAdapter,适配并执行 Handler
-
DispatcherServlet拿到HandlerExecutionChain后,不直接调用 Handler(因为 Handler 可能是注解式、XML 配置式等,形式不统一),而是调用 HandlerAdapter(默认是RequestMappingHandlerAdapter)。 -
HandlerAdapter负责 “适配” Handler:- 解析请求参数(如路径参数、请求体、RequestParam 等),并注入到 Handler 方法的参数中(如
list(Integer page, String name)); - 执行拦截器的
preHandle()方法(拦截器前置处理,如校验登录状态,返回true则继续,false则终止流程); - 调用 Handler 方法(
UserController.list()),执行业务逻辑(如调用 Service 查询数据库,获取用户列表数据)。
- 解析请求参数(如路径参数、请求体、RequestParam 等),并注入到 Handler 方法的参数中(如
5. Handler 执行业务逻辑,返回 ModelAndView
-
UserController.list()方法执行业务逻辑(如调用UserService.queryUsers()),查询到用户列表数据后,返回一个 ModelAndView 对象:Model:存储业务数据(如model.addAttribute("userList", userList)),本质是一个 Map 结构;View:逻辑视图名(如return "user/list",表示视图名为user/list,不包含后缀和路径)。
-
若 Handler 没有返回
ModelAndView(如@ResponseBody注解的接口),则直接返回数据(JSON/XML),后续流程跳过 “视图渲染” 步骤(直接返回响应)。
6. 执行拦截器的 postHandle () 方法(拦截器后置处理)
- Handler 执行完成后,
HandlerAdapter触发拦截器的postHandle()方法(在视图渲染前执行)。 - 可通过该方法修改
ModelAndView(如统一添加全局数据、修改视图名)。
7. DispatcherServlet 调用 ViewResolver,解析逻辑视图
-
DispatcherServlet拿到ModelAndView后,调用 ViewResolver(视图解析器) (默认是InternalResourceViewResolver,处理 JSP)。 -
ViewResolver根据逻辑视图名(user/list)和配置的视图前缀 / 后缀(如前缀/WEB-INF/views/、后缀.jsp),解析为物理视图路径:- 逻辑视图名
user/list→ 物理路径/WEB-INF/views/user/list.jsp。
- 逻辑视图名
-
ViewResolver返回一个具体的View对象(如JstlView,对应 JSP 视图)。
8. View 渲染视图,填充 Model 数据
DispatcherServlet将Model中的数据(如userList)传递给View对象。View渲染页面(如 JSP 解析 EL 表达式${userList},Thymeleaf 解析${userList}),生成 HTML 等响应内容。
9. 执行拦截器的 afterCompletion () 方法(拦截器最终处理)
- 视图渲染完成后,触发拦截器的
afterCompletion()方法(无论流程成功 / 失败都会执行)。 - 可通过该方法释放资源(如关闭流、清理线程局部变量)。
10. DispatcherServlet 返回响应,流程结束
DispatcherServlet将渲染后的响应内容(HTML/JSON 等)通过 Tomcat 返回给客户端,浏览器接收后展示页面或解析数据。
三、关键注意点(避坑 / 面试重点)
-
拦截器执行顺序:
preHandle():按拦截器配置顺序执行(先配置先执行);postHandle():按拦截器配置逆序执行(后配置先执行);afterCompletion():按拦截器配置逆序执行(后配置先执行)。
-
@ResponseBody 特殊处理:
- 若 Handler 方法加了
@ResponseBody(或 Controller 加@RestController),HandlerAdapter会将返回值(如 POJO)直接通过HttpMessageConverter转换为 JSON/XML,不返回ModelAndView,跳过 “视图解析” 和 “视图渲染” 步骤,直接返回响应。
- 若 Handler 方法加了
-
异常处理:
- 流程中若发生异常(如 Handler 执行报错),会被
HandlerExceptionResolver(异常解析器)捕获,返回异常视图或 JSON 响应(如@ExceptionHandler注解的方法)。
- 流程中若发生异常(如 Handler 执行报错),会被
-
核心组件的可扩展性:
- 可自定义
HandlerMapping、HandlerAdapter、ViewResolver等组件(如自定义视图解析器支持 Freemarker),替换 SpringMVC 的默认实现。
- 可自定义
四、流程总结(一句话记核心)
请求→DispatcherServlet→HandlerMapping(找 Handler)→HandlerAdapter(执行 Handler + 拦截器)→ModelAndView→ViewResolver(解析视图)→View(渲染)→响应,全程由前端控制器统一调度,组件解耦,流程清晰可扩展。