引言
接下来基于 Spring 源码,主要介绍以下几个问题:
@EnableWebMvc到底干了什么?- 请求从浏览器进来,完整经过哪些组件?
HandlerMapping、HandlerAdapter、ViewResolver分别干嘛用?- 参数是怎么绑定到方法入参的?
- 返回值是怎么变成 JSON / 页面 / 异常信息的?
- 拦截器、异常处理器在源码中哪个节点执行?
一、核心前提:SpringMVC 整体架构
1. 一句话概括流程
浏览器请求 → DispatcherServlet 分发 → 找到对应 Controller 方法 → 执行方法 → 处理返回值 → 响应给浏览器。
2. 九大核心组件(面试必背)
| 组件 | 作用 |
|---|---|
HandlerMapping |
根据请求 URL 找到对应的 Controller 方法 |
HandlerAdapter |
统一执行 Controller 方法的适配器 |
ThemeResolver |
不同主题间动态切换 |
ViewResolver |
视图解析器,把逻辑视图名转为真实视图 |
HandlerExceptionResolver |
全局异常处理器 |
LocaleResolver |
国际化解析器 |
MultipartResolver |
文件上传解析器 |
RequestToViewNameTranslator |
默认视图名转换器 |
FlashMapManager |
重定向数据管理器 |
二、入口:@EnableWebMvc 源码解析
@EnableWebMvc 是 JavaConfig 方式手动启用 SpringMVC 的注解,等价于 XML 中的 <mvc:annotation-driven/>。
注意:Spring Boot 项目不推荐、也不需要加它。
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
核心就是导入:DelegatingWebMvcConfiguration。
它会自动向容器注册:
RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver- 各种参数解析器、返回值处理器
- 消息转换器(
MappingJackson2HttpMessageConverter)
一句话 :@EnableWebMvc = 自动装配 SpringMVC 全套核心组件。
三、容器启动:SpringMVC 初始化流程
1. Tomcat 启动 → 加载 DispatcherServlet
DispatcherServlet 本质是一个 Servlet,生命周期:init() → service() → destroy()。
2. init 阶段核心:初始化九大组件
java
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); // 文件上传
initLocaleResolver(context); // 国际化
initThemeResolver(context);
initHandlerMappings(context); // 路由映射
initHandlerAdapters(context); // 执行适配器
initHandlerExceptionResolvers(context); // 异常处理
initRequestToViewNameTranslator(context);
initViewResolvers(context); // 视图解析
initFlashMapManager(context);
}
这就是 SpringMVC 启动时干的所有事。
四、请求执行全流程
浏览器发送 HTTP 请求
Tomcat 接收请求,交给 DispatcherServlet
doService(req, resp)
doDispatch(req, resp)
【核心总调度方法】
- getHandler(request)
遍历 HandlerMapping,找到对应 Controller 方法
2. getHandlerAdapter(handler)
找到能执行该方法的适配器
3. 执行拦截器 applyPreHandle
调用 preHandle
4. adapter.handle(request, response, handler)
真正执行 Controller 方法
内部:参数解析 → 执行方法 → 得到返回值
5. 处理返回值
(JSON/视图/文件等)
6. 执行拦截器 applyPostHandle
调用 postHandle
7. 异常处理
(执行异常解析器)
8. 渲染视图
(如果不是直接响应)
9. 执行拦截器 triggerAfterCompletion
调用 afterCompletion
响应回浏览器
五、核心方法 doDispatch 源码解析
doDispatch 源码部分内容如下:
java
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 1. 找到对应的处理器(Controller方法)
mappedHandler = getHandler(processedRequest);
// 2. 找到适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 执行拦截器 preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4. 【真正调用Controller方法】
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 5. 执行拦截器 postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 6. 处理结果、渲染视图、异常处理
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 最终拦截器
mappedHandler.triggerAfterCompletion(processedRequest, response, ex);
}
}
六、关键节点深度拆解
1. 根据 URL 找到 Controller 方法
流程图位置 : doDispatch → 1. getHandler(request)
- 所在类 :
org.springframework.web.servlet.DispatcherServlet - 所在方法 :
doDispatch - 核心代码 :
mappedHandler = getHandler(processedRequest);
核心实现:
- 遍历容器中所有
HandlerMapping - 由
RequestMappingHandlerMapping负责匹配 - 建立并返回
url→HandlerMethod的映射 - 封装为
HandlerExecutionChain(包含所有拦截器)
2. 找到执行方法的适配器
流程图位置 : doDispatch → 2. getHandlerAdapter(handler)
- 所在类 :
DispatcherServlet - 所在方法 :
doDispatch - 核心代码 :
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
核心实现:
- 遍历所有
HandlerAdapter - 匹配到
RequestMappingHandlerAdapter继承自AbstractHandlerMethodAdapter - 用于统一执行
@RequestMapping方法
3. 执行拦截器 preHandle
流程图位置 : doDispatch → 3. 执行拦截器 preHandle
- 所在类 :
DispatcherServlet - 所在方法 :
doDispatch - 核心代码:
java
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
实际执行类 :HandlerExecutionChain
java
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptors.size(); i++) {
HandlerInterceptor interceptor = this.interceptors.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
关键点 :任一拦截器返回
false,直接中断请求,并执行已通过拦截器的afterCompletion。
4. 真正执行 Controller 方法
流程图位置 : doDispatch → 4. adapter.handle(...)
- 所在类 :
DispatcherServlet - 所在方法 :
doDispatch - 核心代码 :
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
实际执行类 :RequestMappingHandlerAdapter
4.1 参数解析
调度入口 :RequestMappingHandlerAdapter
执行类 :ServletInvocableHandlerMethod
遍历所有参数解析器,处理:
@RequestParam@PathVariable@RequestBody@RequestHeaderServletRequest/HttpServletResponse
4.2 反射执行目标方法
所在类 :InvocableHandlerMethod
方法 :doInvoke
java
return method.invoke(getBean(), getArguments());
执行链路:
ha.handle()
↓
handleInternal()
↓
invokeHandlerMethod()
↓
invocableMethod.invokeAndHandle()
↓
invokeForRequest()
↓
【doInvoke()】 ← 最终执行到这里
↓
method.invoke(bean, args) → 反射调用Controller方法
5. 处理返回值(JSON / 视图)
流程图位置 : 执行方法后 → 5. 处理返回值
- 所在类 :
ServletInvocableHandlerMethod - 方法 :
invokeAndHandle - 核心组件 :
HandlerMethodReturnValueHandlerComposite
常见实现:
RequestResponseBodyMethodProcessor:处理@ResponseBody→ JSONViewNameMethodReturnValueHandler:处理字符串视图名ModelAndViewMethodReturnValueHandler:处理ModelAndView
6. 执行拦截器 postHandle
流程图位置 : doDispatch → 6. 执行拦截器 postHandle
- 所在类 :
DispatcherServlet - 所在方法 :
doDispatch - 核心代码 :
mappedHandler.applyPostHandle(processedRequest, response, mv);
实际执行类 :HandlerExecutionChain
java
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
for (int i = this.interceptors.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptors.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
注意 :
postHandle是逆序执行。
preHandle:正序执行postHandle:逆序执行afterCompletion:逆序执行
7. 渲染视图
流程图位置 : doDispatch → 7. 渲染视图
- 所在类 :
DispatcherServlet - 所在方法 :
processDispatchResult - 核心代码 :
render(mv, request, response);
逻辑:
- 通过
ViewResolver解析视图名得到View - 执行
view.render (model, request, response) - 适用于 JSP/Thymeleaf/Freemarker 等模板
8. 执行拦截器 afterCompletion
流程图位置 : doDispatch → 8. 执行拦截器 afterCompletion
- 所在类 :
DispatcherServlet - 位置 :
doDispatch最终catch块 - 核心代码 :
mappedHandler.triggerAfterCompletion(processedRequest, response, ex);
实际执行类 :HandlerExecutionChain
java
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptors.get(i);
interceptor.afterCompletion(request, response, this.handler, ex);
}
}
关键点 :无论正常返回还是抛异常,一定执行。
七、高频面试题
-
SpringMVC 执行流程是什么?
- Tomcat 启动,初始化
DispatcherServlet - 加载 Spring 容器,注册所有 SpringMVC 组件
- 请求进入
doDispatch - 根据 URL 找到
Controller方法 - 执行拦截器前置
- 参数解析 → 调用方法
- 处理返回值(JSON/视图)
- 执行拦截器后置
- 渲染/响应
- 最终拦截器
- Tomcat 启动,初始化
-
DispatcherServlet作用?答:统一入口,总调度,管理九大组件。
-
HandlerMapping和HandlerAdapter区别?答:
Mapping负责找方法,Adapter负责执行方法。 -
@ResponseBody原理?答:返回值处理器 + JSON 消息转换器。
-
拦截器和过滤器区别?
- Filter:Servlet 规范,所有容器都支持,拦截所有请求。
- Interceptor:SpringMVC 组件,能访问 Spring 容器。
-
参数是如何注入的?
答:
ArgumentResolver链式解析。