乐于分享
好东西不私藏

第六篇・Spring 5 源码深度拆解:SpringMVC 全流程核心原理

第六篇・Spring 5 源码深度拆解:SpringMVC 全流程核心原理

👋前言

前面几篇,我们已经把Spring 容器、Bean 生命周期、AOP、事务 四大核心底层全部打通。而 Web 开发中最核心的 SpringMVC,本质就是:在 Web 容器(Tomcat)启动时初始化 Spring 容器,再通过一套统一的分发机制,把 HTTP 请求转发到对应的 @Controller 方法

接下来基于 Spring 源码,主要介绍以下几个问题:

1.@EnableWebMvc到底干了什么?

2.请求从浏览器进来,完整经过哪些组件?

3.HandlerMappingHandlerAdapterViewResolver 分别干嘛用?

4.参数是怎么绑定到方法入参的?

5.返回值是怎么变成 JSON / 页面 异常信息的?

6.拦截器、异常处理器在源码中哪个节点执行?

从请求入口到视图渲染,彻底搞懂Web 底层执行链路

一、核心前提: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 项目不推荐、也不需要加它。  
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(DelegatingWebMvcConfiguration.class)public @interface EnableWebMvc {}

核心就是导入:DelegatingWebMvcConfiguration

它会自动向容器注册:

  • RequestMappingHandlerMapping
  • RequestMappingHandlerAdapter
  • ExceptionHandlerExceptionResolver
  • 各种参数解析器、返回值处理器
  • 消息转换器(MappingJackson2HttpMessageConverter)

一句话:@EnableWebMvc = 自动装配 SpringMVC 全套核心组件

三、容器启动:SpringMVC 初始化流程

1. Tomcat 启动 → 加载 DispatcherServlet

DispatcherServlet 本质是一个 Servlet,生命周期:init() → service() → destroy()

2. init 阶段核心:初始化九大组件

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) 【核心总调度方法】        ↓1. 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 源码部分内容如下

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

if (!mappedHandler.applyPreHandle(processedRequest, response)) {    return;}

实际执行类:HandlerExecutionChain

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
  • @RequestHeader
  • ServletRequest / HttpServletResponse

4.2 反射执行目标方法

所在类:InvocableHandlerMethod方法:doInvoke

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 → JSON
  • ViewNameMethodReturnValueHandler:处理字符串视图名
  • ModelAndViewMethodReturnValueHandler:处理 ModelAndView

6. 执行拦截器 postHandle

流程图位置: doDispatch → 6. 执行拦截器 postHandle

所在类:DispatcherServlet所在方法:doDispatch

mappedHandler.applyPostHandle(processedRequest, response, mv);

实际执行类:HandlerExecutionChain

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);    }}

 注意:逆序执行。 

 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

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);    }}

 关键点:无论正常返回还是抛异常,一定执行。  

七、高频面试题

  1. SpringMVC 执行流程是什么?
1. Tomcat 启动,初始化 DispatcherServlet2. 加载 Spring 容器,注册所有 SpringMVC 组件3. 请求进入 doDispatch4. 根据 URL 找到 Controller 方法5. 执行拦截器前置6. 参数解析 → 调用方法7. 处理返回值(JSON/视图)8. 执行拦截器后置9. 渲染/响应10. 最终拦截器

  1. DispatcherServlet 作用?答:统一入口,总调度,管理九大组件。
  2. HandlerMapping 和 HandlerAdapter 区别?答:Mapping 找方法,Adapter 执行方法。
  3. @ResponseBody 原理?答:返回值处理器 + JSON 消息转换器。
  4. 拦截器和过滤器区别?答: Filter:Servlet 规范,所有容器都支持,拦截所有请求  ;Interceptor 是 SpringMVC 组件,能访问 Spring 容器。
  5. 参数是如何注入的?答:ArgumentResolver 链式解析。

下篇预告

下一篇我们进入 Spring Boot 自动配置原理

  • @SpringBootApplication 三大注解拆解
  • @EnableAutoConfiguration 如何实现自动装配
  • SPI 机制、spring.factories
  • 自定义 Starter 原理与实现