网站首页 > 技术文章 正文
我们来深入源码分析 Spring MVC 的核心流程和关键组件。Spring MVC 是 Spring Framework 提供的用于构建 Web 应用程序的模块,它基于 MVC (Model-View-Controller) 设计模式,提供了强大的灵活性和可扩展性。
Spring MVC 核心组件概览
在深入源码之前,我们先回顾一下 Spring MVC 的核心组件及其职责,这有助于我们理解源码的脉络:
- DispatcherServlet (核心调度器):
- Spring MVC 的前端控制器,所有请求的入口。
- 接收所有 HTTP 请求,并根据配置将请求分发给不同的处理器。
- 负责整个 MVC 流程的协调和控制。
- HandlerMapping (处理器映射器):
- 负责根据请求的 URL 查找匹配的 Handler (处理器)。
- Spring MVC 提供了多种 HandlerMapping 实现,例如 RequestMappingHandlerMapping (基于 @RequestMapping 注解)、SimpleUrlHandlerMapping (基于 URL 模式配置) 等。
- HandlerAdapter (处理器适配器):
- 由于 Handler 可以是不同类型的对象 (例如实现了特定接口的 Bean、使用了注解的普通方法等),HandlerAdapter 负责适配不同类型的 Handler,使其能够被 DispatcherServlet 调用。
- Spring MVC 提供了多种 HandlerAdapter 实现,例如 RequestMappingHandlerAdapter (用于处理使用 @RequestMapping 注解的方法)、HttpRequestHandlerAdapter (用于处理实现了 HttpRequestHandler 接口的 Handler) 等。
- Handler (处理器):
- 实际处理请求的组件,通常是一个方法或一个实现了特定接口的类。
- 负责业务逻辑处理,并返回 ModelAndView 对象 (包含模型数据和视图信息)。
- 在 Spring MVC 中,Handler 通常是 Controller 类中的方法,使用 @RequestMapping 等注解进行标记。
- ModelAndView (模型和视图):
- 用于封装 Handler 处理结果的对象,包含了模型数据 (Model) 和视图信息 (View)。
- Model:用于传递给视图的数据,通常是一个 Map 结构。
- View:视图对象或视图名称,用于指示如何渲染响应。
- ViewResolver (视图解析器):
- 负责根据视图名称解析出具体的 View 对象。
- Spring MVC 提供了多种 ViewResolver 实现,例如 InternalResourceViewResolver (用于解析 JSP 视图)、ThymeleafViewResolver (用于解析 Thymeleaf 视图) 等。
- View (视图):
- 负责将模型数据渲染成最终的响应内容 (例如 HTML, JSON, XML 等)。
- Spring MVC 提供了多种 View 实现,例如 JstlView (用于渲染 JSP 视图)、MappingJackson2JsonView (用于渲染 JSON 视图) 等。
- Interceptor (拦截器):
- 用于在请求处理的不同阶段进行拦截和处理,例如请求预处理、后处理、完成处理等。
- 可以用于实现日志记录、权限验证、性能监控等功能。
- Spring MVC 提供了 HandlerInterceptor 接口,可以自定义拦截器。
- ExceptionResolver (异常解析器):
- 负责处理请求处理过程中发生的异常。
- 可以将异常映射到特定的视图,或者返回特定的错误响应。
- Spring MVC 提供了 HandlerExceptionResolver 接口,可以自定义异常解析器。
Spring MVC 请求处理流程 (源码分析)
我们从 DispatcherServlet 的 doDispatch() 方法开始,逐步分析 Spring MVC 的请求处理流程。doDispatch() 方法是 DispatcherServlet 的核心方法,负责处理每个请求。
以下是
DispatcherServlet.doDispatch() 方法的简化流程 (基于 Spring Framework 5.x 版本,不同版本可能略有差异):
java复制代码// org.springframework.web.servlet.DispatcherServlet.java
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request); // 1. 处理 Multipart 请求 (文件上传)
multipartRequestParsed = (processedRequest != request);
// 2. 查找 HandlerExecutionChain (包含 Handler 和 Interceptors)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response); // 没有找到 Handler
return;
}
// 3. 获取 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 4. 处理 Handler 执行前的 Interceptors (preHandle)
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return; // Interceptor 拦截,请求结束
}
// 5. 执行 Handler (调用 HandlerAdapter 的 handle 方法)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 6. 处理异步请求 (AsyncWebRequest)
if (asyncManager.isConcurrentHandlingStarted()) {
return; // 异步处理,请求交给 AsyncWebRequest 处理
}
applyDefaultViewName(processedRequest, mv); // 设置默认视图名
// 7. 处理 Handler 执行后的 Interceptors (postHandle)
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 8. 处理异常 (Exception Resolution)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex); // 处理 afterCompletion 异常
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// 异步请求完成时触发 afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterCompletion(processedRequest, response, null);
}
}
else {
// 同步请求完成时触发 afterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler, null);
}
if (multipartRequestParsed) {
cleanupMultipart(processedRequest); // 清理 Multipart 请求资源
}
}
}
流程步骤详解和关键源码位置:
- 处理 Multipart 请求 (checkMultipart):
- DispatcherServlet.checkMultipart(HttpServletRequest request)
- 检查请求是否是 multipart/form-data 类型,如果是,则使用 MultipartResolver (例如 StandardServletMultipartResolver) 解析请求,将普通的 HttpServletRequest 包装成 MultipartHttpServletRequest,以便后续可以方便地获取上传的文件。
- 源码位置: org.springframework.web.servlet.DispatcherServlet.checkMultipart() 和 org.springframework.web.multipart.commons.CommonsMultipartResolver 或 org.springframework.web.multipart.support.StandardServletMultipartResolver
- 查找 HandlerExecutionChain (getHandler):
- DispatcherServlet.getHandler(HttpServletRequest request)
- 遍历配置的 HandlerMapping 列表,调用每个 HandlerMapping 的 getHandler() 方法,根据请求 URL 查找匹配的 Handler。
- HandlerMapping 返回的是 HandlerExecutionChain 对象,它包含了找到的 Handler 和一组应用于该 Handler 的 Interceptors。
- 源码位置: org.springframework.web.servlet.DispatcherServlet.getHandler() 和 org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler() 以及各种 HandlerMapping 实现类 (例如 RequestMappingHandlerMapping, SimpleUrlHandlerMapping)
- 获取 HandlerAdapter (getHandlerAdapter):
- DispatcherServlet.getHandlerAdapter(Object handler)
- 遍历配置的 HandlerAdapter 列表,找到能够处理当前 Handler 类型的 HandlerAdapter。
- 源码位置: org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter() 和 org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter, org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter, org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter 等。
- 处理 Handler 执行前的 Interceptors (applyPreHandle):
- HandlerExecutionChain.applyPreHandle(HttpServletRequest request, HttpServletResponse response)
- 遍历 HandlerExecutionChain 中配置的 Interceptors,依次调用每个 Interceptor 的 preHandle() 方法。
- 如果任何一个 preHandle() 方法返回 false,则请求处理流程中断,直接返回。
- 源码位置: org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle() 和 org.springframework.web.servlet.HandlerInterceptor.preHandle()
- 执行 Handler (ha.handle):
- HandlerAdapter.handle(HttpServletRequest request, HttpServletResponse response, Object handler)
- 调用选定的 HandlerAdapter 的 handle() 方法,执行实际的 Handler (Controller 方法)。
- HandlerAdapter 负责适配不同类型的 Handler,并将其调用统一为 ModelAndView 的返回。
- 例如,RequestMappingHandlerAdapter 会处理使用 @RequestMapping 注解的方法,并解析方法参数、调用方法、处理返回值等。
- 源码位置: 各种 HandlerAdapter 实现类的 handle() 方法,例如 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handle()
- 处理异步请求 (asyncManager.isConcurrentHandlingStarted()):
- Spring MVC 支持异步请求处理,如果 Handler 返回的是 Callable, DeferredResult 等异步类型,则会将请求交给 WebAsyncManager 进行异步处理。
- 源码位置: org.springframework.web.context.request.async.WebAsyncManager 和相关类。
- 处理 Handler 执行后的 Interceptors (applyPostHandle):
- HandlerExecutionChain.applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)
- 遍历 HandlerExecutionChain 中配置的 Interceptors,逆序依次调用每个 Interceptor 的 postHandle() 方法。
- postHandle() 方法在 Handler 执行之后、视图渲染之前执行,可以对 ModelAndView 对象进行修改。
- 源码位置: org.springframework.web.servlet.HandlerExecutionChain.applyPostHandle() 和 org.springframework.web.servlet.HandlerInterceptor.postHandle()
- 处理异常 (processDispatchResult):
- DispatcherServlet.processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception ex)
- 如果在请求处理过程中发生异常 (dispatchException 不为 null),则调用 processHandlerException() 方法处理异常。
- 如果没有异常,则进行视图渲染 (render())。
- 源码位置: org.springframework.web.servlet.DispatcherServlet.processDispatchResult() 和 org.springframework.web.servlet.DispatcherServlet.processHandlerException() 以及 org.springframework.web.servlet.DispatcherServlet.render()
- 视图渲染 (render):
- DispatcherServlet.render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)
- 如果 ModelAndView 对象不为空,则根据 ModelAndView 中的视图名称或 View 对象,使用 ViewResolver 解析视图,并调用 View 的 render() 方法进行视图渲染。
- 源码位置: org.springframework.web.servlet.DispatcherServlet.render() 和 org.springframework.web.servlet.ViewResolver.resolveViewName() 以及各种 View 实现类 (例如 JstlView, MappingJackson2JsonView) 的 render() 方法。
- 处理请求完成后的 Interceptors (triggerAfterCompletion):
- DispatcherServlet.triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, Exception ex)
- 遍历 HandlerExecutionChain 中配置的 Interceptors,逆序依次调用每个 Interceptor 的 afterCompletion() 方法。
- afterCompletion() 方法在整个请求处理完成之后 (包括视图渲染和异常处理) 执行,可以进行资源清理、日志记录等操作。
- 源码位置: org.springframework.web.servlet.DispatcherServlet.triggerAfterCompletion() 和 org.springframework.web.servlet.HandlerInterceptor.afterCompletion()
关键源码文件和目录:
- org.springframework.web.servlet.DispatcherServlet.java: 核心调度器 DispatcherServlet 的实现。
- org.springframework.web.servlet.HandlerMapping.java: HandlerMapping 接口定义。
- org.springframework.web.servlet.HandlerAdapter.java: HandlerAdapter 接口定义。
- org.springframework.web.servlet.ViewResolver.java: ViewResolver 接口定义。
- org.springframework.web.servlet.View.java: View 接口定义。
- org.springframework.web.servlet.HandlerInterceptor.java: HandlerInterceptor 接口定义。
- org.springframework.web.servlet.HandlerExceptionResolver.java: HandlerExceptionResolver 接口定义。
- org.springframework.web.servlet.mvc.method.annotation: 基于注解的 HandlerMapping 和 HandlerAdapter 实现 (例如 RequestMappingHandlerMapping, RequestMappingHandlerAdapter)。
- org.springframework.web.servlet.view: 各种 ViewResolver 和 View 实现 (例如 InternalResourceViewResolver, JstlView, MappingJackson2JsonView)。
- org.springframework.web.context.request.async: 异步请求处理相关的类。
总结:
Spring MVC 的源码分析是一个深入理解其工作原理的过程。通过分析
DispatcherServlet.doDispatch() 方法的流程,我们可以清晰地看到 Spring MVC 如何接收请求、查找 Handler、适配 Handler、执行 Handler、处理 Interceptors、解析视图、渲染视图以及处理异常。
学习建议:
- 从 DispatcherServlet 入手: DispatcherServlet 是 Spring MVC 的核心,从 doDispatch() 方法开始跟踪请求处理流程是理解 Spring MVC 的关键。
- 关注接口和抽象类: Spring MVC 中大量使用了接口和抽象类,例如 HandlerMapping, HandlerAdapter, ViewResolver, View, HandlerInterceptor, HandlerExceptionResolver 等。理解这些接口和抽象类的作用,有助于把握 Spring MVC 的扩展点和设计思想。
- 结合调试工具: 使用 IDE 的调试功能,单步跟踪请求处理流程,观察变量的值和方法的调用,可以更直观地理解源码的执行过程。
- 阅读官方文档和示例: Spring Framework 的官方文档和示例代码是学习源码的重要参考资料。
- 逐步深入: Spring MVC 的源码比较庞大,可以先从核心流程入手,逐步深入到各个组件的细节实现。
希望这个 Spring MVC 源码分析能够帮助你更好地理解其内部机制。深入源码学习是一个持续的过程,需要耐心和实践。
猜你喜欢
- 2025-03-20 5千字的SpringMVC总结,我觉得你会需要
- 2025-03-20 javaweb中mvc模式,java注解的实现原理
- 2025-03-20 SpringMVC的工作原理(springmvc工作原理图)
- 2025-03-20 当前最火的web开发技术(web开发用什么技术比较好)
- 2025-03-20 Spring 中的Servlet与Spring MVC 有什么区别?
- 2025-03-20 一张图讲清楚SpringMVC运行原理,拦截器&过滤器区别与执行顺序
- 2025-03-20 SpringMVC访问静态资源(springboot访问静态html)
- 2025-03-20 SpringMVC实战入门教程,四天快速搞定springmvc框架
- 2025-03-20 2022最新SpringMVC面试题附完整答案
- 2025-03-20 撕开SpringMVC的优雅外衣!看程序员如何用暴力拆解参透经典设计
你 发表评论:
欢迎- 最近发表
-
- 宇宙厂:深入聊聊 CJS 和 ESM 模块化三点核心差异?
- #前端高手进阶#一起薅羊毛~
- 前端基础进阶(十):深入详解函数的柯里化
- 2025 年 Object 和 Map 如何选择?
- 为何说 postMessage 才是真正的 setTimeout(0)?
- 为什么高手写 JS 总是又快又好?这10个技巧你要知道
- 2025 年 Deno 终于官宣 pnpm 和 Yarn 可使用 JSR?
- 宇宙厂:为什么前端要了解 Interaction to Next Paint (INP)
- Node.js 原生支持 TypeScript?开发者需要了解的一切
- 请务必用 postTask/isInputPending 释放JS主线程!
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端md5加密 (49)
- 前端路由 (55)
- 前端数组 (65)
- 前端定时器 (47)
- 前端接口 (46)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle约束 (46)
- oracle 中文 (51)
- oracle链接 (47)
- oracle的函数 (57)
- mac oracle (47)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)