当前位置: 首页 > news >正文

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

引言

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

  1. @EnableWebMvc到底干了什么?
  2. 请求从浏览器进来,完整经过哪些组件?
  3. HandlerMappingHandlerAdapterViewResolver分别干嘛用?
  4. 参数是怎么绑定到方法入参的?
  5. 返回值是怎么变成 JSON / 页面 / 异常信息的?
  6. 拦截器、异常处理器在源码中哪个节点执行?

一、核心前提: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@interfaceEnableWebMvc{}

核心就是导入:DelegatingWebMvcConfiguration

它会自动向容器注册:

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

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

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

1. Tomcat 启动 → 加载 DispatcherServlet

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

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

protectedvoidinitStrategies(ApplicationContextcontext){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源码解析

doDispatch源码部分内容如下:

protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse){HttpServletRequestprocessedRequest=request;HandlerExecutionChainmappedHandler=null;try{ModelAndViewmv=null;ExceptiondispatchException=null;try{// 1. 找到对应的处理器(Controller方法)mappedHandler=getHandler(processedRequest);// 2. 找到适配器HandlerAdapterha=getHandlerAdapter(mappedHandler.getHandler());// 3. 执行拦截器 preHandleif(!mappedHandler.applyPreHandle(processedRequest,response)){return;}// 4. 【真正调用Controller方法】mv=ha.handle(processedRequest,response,mappedHandler.getHandler());// 5. 执行拦截器 postHandlemappedHandler.applyPostHandle(processedRequest,response,mv);}catch(Exceptionex){dispatchException=ex;}// 6. 处理结果、渲染视图、异常处理processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException);}catch(Exceptionex){// 最终拦截器mappedHandler.triggerAfterCompletion(processedRequest,response,ex);}}

六、关键节点深度拆解

1. 根据 URL 找到 Controller 方法

流程图位置doDispatch1. getHandler(request)

  • 所在类org.springframework.web.servlet.DispatcherServlet
  • 所在方法doDispatch
  • 核心代码mappedHandler = getHandler(processedRequest);

核心实现

  • 遍历容器中所有HandlerMapping
  • RequestMappingHandlerMapping负责匹配
  • 建立并返回urlHandlerMethod的映射
  • 封装为HandlerExecutionChain(包含所有拦截器)

2. 找到执行方法的适配器

流程图位置doDispatch2. getHandlerAdapter(handler)

  • 所在类DispatcherServlet
  • 所在方法doDispatch
  • 核心代码HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

核心实现

  • 遍历所有HandlerAdapter
  • 匹配到RequestMappingHandlerAdapter继承自AbstractHandlerMethodAdapter
  • 用于统一执行@RequestMapping方法

3. 执行拦截器preHandle

流程图位置doDispatch3. 执行拦截器 preHandle

  • 所在类DispatcherServlet
  • 所在方法doDispatch
  • 核心代码
if(!mappedHandler.applyPreHandle(processedRequest,response)){return;}

实际执行类HandlerExecutionChain

booleanapplyPreHandle(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{for(inti=0;i<this.interceptors.size();i++){HandlerInterceptorinterceptor=this.interceptors.get(i);if(!interceptor.preHandle(request,response,this.handler)){triggerAfterCompletion(request,response,null);returnfalse;}this.interceptorIndex=i;}returntrue;}

关键点:任一拦截器返回false,直接中断请求,并执行已通过拦截器的afterCompletion

4. 真正执行 Controller 方法

流程图位置doDispatch4. 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

returnmethod.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

流程图位置doDispatch6. 执行拦截器 postHandle

  • 所在类DispatcherServlet
  • 所在方法doDispatch
  • 核心代码mappedHandler.applyPostHandle(processedRequest, response, mv);

实际执行类HandlerExecutionChain

voidapplyPostHandle(HttpServletRequestrequest,HttpServletResponseresponse,ModelAndViewmv)throwsException{for(inti=this.interceptors.size()-1;i>=0;i--){HandlerInterceptorinterceptor=this.interceptors.get(i);interceptor.postHandle(request,response,this.handler,mv);}}

注意postHandle逆序执行。

  • preHandle:正序执行
  • postHandle:逆序执行
  • afterCompletion:逆序执行

7. 渲染视图

流程图位置doDispatch7. 渲染视图

  • 所在类DispatcherServlet
  • 所在方法processDispatchResult
  • 核心代码render(mv, request, response);

逻辑

  • 通过ViewResolver解析视图名得到View
  • 执行view.render (model, request, response)
  • 适用于 JSP/Thymeleaf/Freemarker 等模板

8. 执行拦截器afterCompletion

流程图位置doDispatch8. 执行拦截器 afterCompletion

  • 所在类DispatcherServlet
  • 位置doDispatch最终catch
  • 核心代码mappedHandler.triggerAfterCompletion(processedRequest, response, ex);

实际执行类HandlerExecutionChain

voidtriggerAfterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Exceptionex)throwsException{for(inti=this.interceptorIndex;i>=0;i--){HandlerInterceptorinterceptor=this.interceptors.get(i);interceptor.afterCompletion(request,response,this.handler,ex);}}

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

七、高频面试题

  1. SpringMVC 执行流程是什么?

    1. Tomcat 启动,初始化DispatcherServlet
    2. 加载 Spring 容器,注册所有 SpringMVC 组件
    3. 请求进入doDispatch
    4. 根据 URL 找到Controller方法
    5. 执行拦截器前置
    6. 参数解析 → 调用方法
    7. 处理返回值(JSON/视图)
    8. 执行拦截器后置
    9. 渲染/响应
    10. 最终拦截器
  2. DispatcherServlet作用?
    答:统一入口,总调度,管理九大组件。

  3. HandlerMappingHandlerAdapter区别?
    答:Mapping负责找方法,Adapter负责执行方法。

  4. @ResponseBody原理?
    答:返回值处理器 + JSON 消息转换器。

  5. 拦截器和过滤器区别?

    • Filter:Servlet 规范,所有容器都支持,拦截所有请求。
    • Interceptor:SpringMVC 组件,能访问 Spring 容器。
  6. 参数是如何注入的?
    答:ArgumentResolver链式解析。

http://www.jsqmd.com/news/896939/

相关文章:

  • 2026年10款论文降AIGC工具横评:从90%降至10%的硬核之选 - 降AI小能手
  • 为什么LiteIDE是Go开发者的终极效率工具?完整指南揭秘
  • Unity游戏里做个动态时钟UI?用C#的DateTime.Now和ToString(),5分钟搞定!
  • 专业、智能、合规、省心,倍盈通代理记账八大核心优势,重新定义深圳财税服务标准 - GrowthUME
  • 浏览器端视频转音频技术实现:Web Audio API 实战
  • 信创环境下如何实现稳定的UI自动化?深度解构AI Agent在企业级架构中的非侵入式落地实践
  • SAP B1 在Web Client里的AI数据分析(FP2608版本)
  • Unity新手村速成:5分钟搞定你的第一个森林湖泊场景(含Terrain工具详解)
  • 2026年国内主流的智能语音机器人评测:五款高实用性方案深度解析 - 品牌2025
  • SmartTube终极指南:如何在Android TV上打造无广告YouTube观影体验
  • 探秘威海知名游艇俱乐部,开启游艇出海海上浪漫之旅! - GrowthUME
  • 终极指南:免费开源Crimson字体如何为你的设计增添专业质感
  • Python开发者五分钟完成Taotoken多模型api密钥配置与调用
  • 江门市黄金回收全域攻略:5月25日高位金价下,六区四市居民如何安全变现? - 润富黄金珠宝行
  • Vue3父子组件通信全攻略
  • 5分钟掌握国家中小学智慧教育平台电子课本下载:tchMaterial-parser智能解析工具完全指南
  • 「 论文投稿 」《International Journal of Robotics Research》录用经历
  • 绿色物联网硬件节能技术:从M2M通信到MCU的能效优化实战
  • [特殊字符] 你的论文重复率有多高?用这个免费工具3分钟就能知道
  • 冰雪传奇点卡版官网:特色单职业多流派玩法解锁多样冰雪冒险体验
  • 初创公司如何利用Taotoken管理多个AI项目的API成本
  • Windows消息防撤回完整指南:微信QQ防撤回工具全面解析
  • 告别插件!在Unity中自制高性能小地图的3个核心优化技巧(URP/移动端适用)
  • 怎样轻松下载网络视频资源?3分钟掌握开源下载神器
  • 2026化妆培训学校哪家靠谱?内行真实测评,想学化妆别乱选 - 品牌测评鉴赏家
  • 为开源项目OpenClaw配置Taotoken作为其大模型供应商的步骤
  • UnisonFlow:基于SDN与MPI感知的高性能计算网络协同优化实践
  • 现在不掌握ChatGPT攻略生成,3个月内将被淘汰——游戏MCN机构内部培训PPT首次公开(含可商用Prompt库+效果评估SOP)
  • 深入解析B站视频下载器:如何高效获取会员专属4K内容的技术实现
  • 02 飞书H5应用JSSDK鉴权实战:从零到一构建安全前端交互