SpringMVC 笔记 - 11 - SpringMVC 执行流程
学习思路:先看总源码 → 按执行顺序逐段拆解 → 每步贴源码 + 解析 + 作用,对照阅读最容易理解
一、总入口:DispatcherServlet 核心总源码
java
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1. 获取处理器执行链
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
// 2. 获取处理器适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 执行所有拦截器 preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4. 执行控制器方法,返回 ModelAndView
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 5. 执行所有拦截器 postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 6. 处理结果:视图渲染 + 执行 afterCompletion
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}

二、服务器启动时做了什么?(前置必备)
1. 继承关系
DispatcherServlet
→ FrameworkServlet
→ HttpServletBean
→ HttpServlet
→ GenericServlet
→ Servlet
DispatcherServlet 本质就是一个 Servlet,由 Web 服务器加载管理。
2. 启动初始化流程(源码链路)
java
init() → initServletBean() → initWebApplicationContext() → onRefresh() → initStrategies()
服务器启动阶段,DispatcherServlet的构造函数被执行,
并且调用init()函数,进行初始化
DispatcherServlet类中并没有init()方法
在HttpServlet类中,
java
public void init(ServletConfig config) throws ServletException {
super.init(config);
this.legacyHeadHandling = Boolean.parseBoolean(config.getInitParameter("jakarta.servlet.http.legacyDoHead"));
}
调用了父类GenericServlet的init()方法
在GenericServlet类中,
java
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
init()方法交由子类进行重写。
也就是子类HttpServletBean中进行重写。
在HttpServletBean类中,
java
public final void init() throws ServletException {
this.initServletBean();
}
protected void initServletBean() throws ServletException {
}
发现init()方法中调用了initServletBean()方法,
initServletBean()由子类FrameworkServlet进行重写。
在FrameworkServlet类中,
java
protected final void initServletBean() throws ServletException {
this.webApplicationContext = this.initWebApplicationContext();
}
protected WebApplicationContext initWebApplicationContext() {
this.onRefresh(wac);
}
protected void onRefresh(ApplicationContext context) {
}
在initWebApplicationContext()方法中,调用了onRefresh()方法
onRefresh()方法由子类DispatcherServlet进行重写。
在DispatcherServlet类中,
java
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
最终执行this.initStrategies(context);
3. initStrategies 初始化九大组件
java
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); // 文件上传解析器
initLocaleResolver(context); // 国际化解析器
initThemeResolver(context); // 主题解析器
initHandlerMappings(context); // 处理器映射器
initHandlerAdapters(context); // 处理器适配器
initHandlerExceptionResolvers(context); // 异常解析器
initRequestToViewNameTranslator(context); // 视图名转换器
initViewResolvers(context); // 视图解析器
initFlashMapManager(context); // 重定向数据管理器
}
一句话总结:
服务器启动 → 初始化 IOC 容器 → 初始化所有 HandlerMapping、HandlerAdapter、ViewResolver → 建立 URL 与 Controller 方法映射。

三、逐行源码精讲(请求执行全过程)
第 1 步:获取处理器执行链 HandlerExecutionChain
对应源码
java
// doDispatch 第一行
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
getHandler 源码
java
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 遍历所有处理器映射器
// 通过合适的HandlerMapping才能获取到HandlerExecutionChain对象。
// 如果处理器方法使用了@RequestMapping注解,那么以下代码中的mapping是:RequestMappingMapping对象
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
解析
- 遍历所有 HandlerMapping集合(启动时已创建)
- 根据 请求 URL 查找对应的 HandlerMethod
- 封装成 HandlerExecutionChain(处理器执行链)
我们处理请求的第一步代码是:
java
HandlerExecutionChain mapperHandler = getHandler(processedRequest);
其本质上是调用了:
java
HandlerExecutionChain handler = mapping.getHandler(request)
HandlerMapping 是 SpringMVC 的处理器映射器顶层接口 ,是请求映射的核心规范,唯一职责 :根据请求路径(URL)找到对应的处理器方法(HandlerMethod)。
HandlerMapping 提供多种实现,适配不同的映射方式:
RequestMappingHandlerMapping(最常用)- 专门处理 @RequestMapping / @GetMapping / @PostMapping 等注解
- 项目中 99% 场景使用此实现
SimpleUrlHandlerMapping- 基于 XML 配置或手动配置 URL 与处理器映射
- 适用于老式配置、静态资源映射等场景
BeanNameUrlHandlerMapping- 根据 Bean 的名称作为 URL 进行映射
总结:用注解就用
RequestMappingHandlerMapping;用 XML 配置就用其他实现类。
HandlerMapping 的创建时机
-
所有 HandlerMapping 对象,都在 Web 服务器启动阶段创建
-
创建后统一存入 DispatcherServlet 的集合中:
javaList<HandlerMapping> handlerMappings; -
服务器启动时,SpringMVC 会扫描所有 HandlerMapping 实现并自动注册
-
同时完成 URL 与 HandlerMethod 的映射关系初始化
这一步执行过程中,直接关联的核心类如下:
- HandlerMapping
- 顶层接口,定义映射规范
- RequestMappingHandlerMapping
- 最常用实现类,处理 @RequestMapping 注解
- HandlerExecutionChain
- 封装本次请求的处理器 + 拦截器
- HandlerMethod
- 封装目标 Controller 方法(beanName + Method 反射对象)
- HandlerInterceptor
- 拦截器接口,被存入执行链的 interceptorList 中
HandlerExecutionChain 结构
java
public class HandlerExecutionChain { // HandlerExecutionChain: 处理器执行链对象
// 真正要执行的 Controller 方法
Object handler = new HandlerMethod(......) // 实际是 HandlerMethod
// 本次请求所有拦截器
private List<HandlerInterceptor> interceptorList;
}
作用
找到 "这次请求该执行哪个方法 + 经过哪些拦截器"
HandlerMethod 是什么?
HandlerMethod是最核心的要执行的目标,处理器方法
HandlerMethod是在web服务器启动时初始化spring容器的时候,就创建好了。
这个类当中比较重要的属性包括:beanName和Method
例如,以下代码:
java
@Controller("userController")
public class UserController{
@RequestMapping("/login")
public String login(User user){
return ....;
}
}
那么以上代码对应了一个HandlerMethod对象:
java
public class HandlerMethod{
private String beanName = "userController";
private Method method = UserController.class.getMethod("login", User.class);
}
第 2 步:获取处理器适配器 HandlerAdapter
对应源码
java
// doDispatch 第二行
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
getHandlerAdapter 源码
java
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// 判断适配器是否支持当前处理器
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler...");
}
解析
- 遍历所有 HandlerAdapter
- 调用
supports(handler)匹配 - 返回对应适配器(最常用:RequestMappingHandlerAdapter)
为什么必须用适配器?
// 当前执行代码
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
1. 基础定位
- HandlerAdapter 是处理器适配器顶层接口 ,底层采用适配器模式。
- 每一种处理器(Controller/HandlerMethod)都有与之匹配的适配器。
- 核心职责:参数处理、数据绑定、类型转换、方法调用、返回值封装。
2. 常用实现类
- RequestMappingHandlerAdapter(最常用)
- 专门适配标注 @RequestMapping / @GetMapping / @PostMapping的处理器方法。
- 其他适配器:适配老式 Controller 接口、HttpRequestHandler 等。
3. 获取 Handler 类型
mappedHandler.getHandler()获取到的是 HandlerMethod 对象。- HandlerMethod 封装了目标 Controller 的 beanName 与 Method 反射信息。
4. 创建与存储时机
-
所有 HandlerAdapter 实现类 在 服务器启动阶段就已创建。
-
统一存入 DispatcherServlet 集合:
javaList<HandlerAdapter> handlerAdapters;
5. 引入 HandlerAdapter 的核心原因
为了遵循开闭原则 + 彻底解耦
DispatcherServlet 只负责调度,不关心 Handler 是什么、怎么执行。
6. 使用 HandlerAdapter 的三大核心理由
① 统一接口,适配多种 Handler 类型(适配器模式)
SpringMVC 支持多种处理器:
-
HandlerMethod:@Controller + @RequestMapping 注解方式(主流)
-
Controller 接口:传统实现 Controller 接口的控制器
-
HttpRequestHandler:处理静态资源、底层 HTTP 请求
-
有的 Handler 是 方法(HandlerMethod)
-
有的 Handler 是 类(Controller 接口)
-
有的 Handler 是 Servlet
-
有的 Handler 直接操作 response
-
有的 Handler 返回 ModelAndView
-
有的 Handler 返回 void
调用方式完全不一样!
如果不用适配器,DispatcherServlet 会出现大量 instanceof 判断:
java
// 不使用适配器的丑陋代码(违反开闭原则)
Object handler = mappedHandler.getHandler();
if (handler instanceof HandlerMethod) {
// 解析参数、反射调用...
} else if (handler instanceof Controller) {
// 强制转换、调用 handleRequest...
} else if (handler instanceof HttpRequestHandler) {
// 调用 handleRequest...
}
新增处理器必须改 DispatcherServlet 源码,严重违反开闭原则。
使用适配器后代码极简:
java
HandlerAdapter ha = getHandlerAdapter(handler);
ModelAndView mv = ha.handle(request, response, handler);
DispatcherServlet 完全不关心 Handler 类型,只调用适配器。
② 封装 "脏活累活":复杂逻辑全部交给适配器
HandlerMethod 只是方法元数据(通过反射获取的 Method 对象等元数据),自己无法执行。
适配器(尤其 RequestMappingHandlerAdapter)负责:
- 参数解析:从 Request 中提取 @RequestParam、@RequestBody 等参数
- 数据绑定:WebDataBinder 完成字符串→类型转换
- 消息转换:HttpMessageConverter 实现 JSON ↔ POJO
- 参数校验:处理 @Valid 校验逻辑
- 反射调用:执行 Controller 目标方法
- 返回值处理:将 String/ResponseEntity/void 统一处理
适配器让 DispatcherServlet 保持极简、专注调度。
HandlerMethod 只是一个方法的描述(通过反射获取的 Method 对象等元数据)。
它自己是不会执行的,而且直接反射调用它非常复杂。
对于一个 Controller 方法:
java
@RequestMapping("/hello")
public String sayHello(@RequestParam String name, @RequestBody User user, HttpServletRequest request) {
return "success";
}
DispatcherServlet 拿到这个 HandlerMethod 后,面临巨大的挑战:
- 参数解析:方法需要 name,需要 user 对象,需要 request。
- 这些数据从哪里来?
- 如何从 HTTP 请求中解析出来?
- 如何把 JSON 转成 User 对象?
- 数据绑定:如何把 String 类型的 "18" 绑定到 Integer 类型的参数上?
- 验证:如果有 @Valid,如何执行校验?
- 返回值处理:方法返回 "success" 字符串,是指跳转页面,还是直接响应文本,还是 JSON?
这就是 HandlerAdapter(特别是 RequestMappingHandlerAdapter)存在的意义:
它内部包含了大量的 ArgumentResolver(参数解析器) 和 ReturnValueHandler(返回值处理器)。它负责:
- 分析方法签名。
- 把 HTTP 请求的数据"适配"成方法需要的参数。
- 反射调用你的 Controller 方法。
- 把方法的返回值"适配"成 DispatcherServlet 能看懂的 ModelAndView(或者直接处理完响应)。
③ 统一返回结构,标准化流程
不同 Handler 返回值五花八门:
- 返回 String(视图名)
- 返回 ResponseEntity
- 返回 void
- 直接操作输出流
HandlerAdapter 的 handle() 方法约定:
统一返回 ModelAndView(或 null)
让 DispatcherServlet 后续渲染流程标准化、稳定、可预期。
总结
HandlerAdapter 是处理器的 "万能翻译官":
把不同类型的 Handler、复杂的参数绑定、多样的返回值,全部适配成 DispatcherServlet 能统一处理的标准格式 ,同时保证开闭原则与高度扩展性。
第 3 步:执行拦截器 preHandle
对应源码
java
// doDispatch 第三段
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
applyPreHandle 源码
java
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
// 只要一个返回 false,直接触发 afterCompletion 并中断请求
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
解析
- 正序执行 所有拦截器
preHandle() - 任何一个返回
false,直接终止整个流程 - 常用于:登录校验、权限拦截、日志、请求限流
- 遍历List集合中,从List集合中取出每一个 HandlerInterceptor对象,调用 preHandle,i++,可见是顺序调用。
第 4 步:执行 Controller 方法(核心业务)
对应源码
java
// doDispatch 第四段
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
mv 是ModelAndView对象
ha 是处理器适配器,HandlerAdapter
如果是@RequestMapping注解对应的,那么就是 RequestMappingHandlerAdapter
这个方法是最核心的,调用请求路径对应的HandlerMethod。(调用处理器方法)
内部核心流程
java
// RequestMappingHandlerAdapter 内部
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
ModelAndView mav = this.invokeHandlerMethod(request, response, handlerMethod);
retuern mav;
}
protected ModelAndView invokeHandlerMethod(...) {
// 1. 创建数据绑定工厂 WebDataBinder
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 2. 创建可执行方法对象
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 3. 参数解析 → 数据绑定 → 反射调用方法
// 3.1 给可调用的方法绑定数据
invocableMethod.setDataBinderFactory(binderFactory);
// 3.2 给可调用的方法设置参数
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 3.3 可调用的方法执行
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
}
HandlerAdapter 中完成的核心工作
- 参数解析:从 request 中提取请求数据
- 数据转换:如果是 JSON/XML 等请求体数据, 调用 HttpMessageConverter 将其转换为 POJO 对象。
- 数据绑定: 通过 WebDataBinder 将转换后的数据绑定到 HandlerMethod 的方法参数上。
- 执行调用:反射执行目标 Controller 方法(HandlerMethod)。
- 结果封装:将方法返回值封装为 ModelAndView 对象。
HttpMessageConverter 调用时机
在 HandlerAdapter#handle() 方法内部,执行流程:
- 解析方法参数
- 判断参数是否需要消息转换
- 是否标注
@RequestBody - 是否是 JSON/XML 等格式数据
- 是否标注
- 如果需要 → 调用 HttpMessageConverter
- 将请求体 JSON/XML → 转为 POJO
- 数据绑定完成
- 反射调用 Controller 方法
- 返回值如果是 @ResponseBody → 再次调用 HttpMessageConverter
- 将 POJO → JSON/XML 输出
第 5 步:执行拦截器 postHandle
对应源码
java
// doDispatch 第五段
mappedHandler.applyPostHandle(processedRequest, response, mv);
applyPostHandle 源码
java
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
// 倒序执行
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
解析
- 倒序执行 所有拦截器
postHandle() - 方法执行完毕、视图渲染之前执行
- 可修改 ModelAndView 中的数据或视图名
- 常用于:统一数据包装、日志、敏感信息过滤
- 通过源码,可以很轻松的看到,从List集合中逆序(i--)逐一取出拦截器对象,并且调用拦截器的 postHandle方法。
第 6 步:处理结果(渲染 + afterCompletion)
对应源码
java
// doDispatch 最后一行
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
processDispatchResult 源码
java
private void processDispatchResult(...) throws Exception {
// 1. 视图渲染
render(mv, request, response);
// 2. 执行拦截器 afterCompletion
mappedHandler.triggerAfterCompletion(request, response, null);
}
子步骤 6.1:视图渲染 render
对应源码
java
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1. 解析视图名 → 得到 View 对象
View view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
// 2. 执行视图渲染
view.render(mv.getModelInternal(), request, response);
}
resolveViewName 源码
java
protected View resolveViewName(...) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
解析
- 遍历 ViewResolver(如 InternalResourceViewResolver、ThymeleafViewResolver)
- 把逻辑视图名 (如 success)解析为 View 对象
- 调用
view.render()渲染页面 / 数据,响应浏览器
子步骤 6.2:执行 afterCompletion
对应源码
java
mappedHandler.triggerAfterCompletion(request, response, null);
triggerAfterCompletion 源码
java
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) {
// 倒序执行
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable ex2) {
logger.error("afterCompletion threw exception", ex2);
}
}
}
解析
- 倒序执行
- 无论是否异常,一定执行(类似 finally)
- 常用于:资源释放、耗时统计、日志收尾、清理 ThreadLocal
- 通过源码可以看出,也是通过逆序(i--)的方式进行拦截器的调用,调用拦截器的afterCompletion方法。
四、完整执行流程
- 请求 → DispatcherServlet
- HandlerMapping → 获取 HandlerExecutionChain
- HandlerAdapter → 获取对应适配器
- 正序执行拦截器 preHandle
- 执行 Controller 方法 → 返回 ModelAndView
- 倒序执行拦截器 postHandle
- ViewResolver 解析视图 → View 渲染响应
- 倒序执行拦截器 afterCompletion

五、核心对象职责
| 对象 | 核心作用 |
|---|---|
| DispatcherServlet | 前端控制器,统一调度所有流程 |
| HandlerMapping | 根据 URL 找 Controller 方法 |
| HandlerExecutionChain | 封装 Handler + 所有拦截器 |
| HandlerAdapter | 适配并调用 Controller 方法 |
| HandlerMethod | 封装 Controller 方法(反射用) |
| ModelAndView | 封装业务数据 + 逻辑视图名 |
| ViewResolver | 视图名 → View 对象 |
| View | 渲染页面,响应浏览器 |
| HandlerInterceptor | 拦截器:pre/post/after 三段处理 |