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

图解SpringMVC工作流程,以及源码分析。

本篇系统地图解和分析Spring MVC的工作流程及其核心源码。这将分为两部分:工作流程图解核心源码分析


第一部分:Spring MVC 工作流程图解

Spring MVC的核心是一个围绕DispatcherServlet设计的“前端控制器”(Front Controller)模式。所有请求都会先经过它,再由它委托给其他组件进行处理。

下图清晰地展示了一个HTTP请求从发起到响应的完整生命周期,以及Spring MVC核心组件在其中扮演的角色:

Spring MVC Core Components
返回处理链
调用实际Controller
返回ModelAndView
返回ModelAndView
返回View对象
渲染并返回响应
HandlerMapping
DispatcherServlet
HandlerAdapter
Controller
ViewResolver
View
HTTP Response
HTTP Request
HandlerExecutionChain
包含Handler和Interceptors
Service/DAO等业务层

上述流程可以概括为以下几个关键步骤:

  1. 发送请求:用户发起一个HTTP请求到web服务器,匹配DispatcherServlet的映射路径(如/)。
  2. 请求委派DispatcherServlet是流量入口,负责协调所有组件,但它自己不处理业务。
  3. 查找HandlerDispatcherServlet查询一个或多个HandlerMapping,找到处理该请求的Handler(通常是Controller类中的一个方法)和所有匹配的Interceptor,封装成一个HandlerExecutionChain
  4. 执行拦截器:按顺序执行HandlerExecutionChain中所有InterceptorpreHandle方法。若某个preHandle返回false,则流程中断,直接返回。
  5. 适配并调用DispatcherServlet通过HandlerAdapter来实际执行找到的Handler。适配器模式使得不同类型的Handler(如@Controller, Controller接口, HttpRequestHandler)都能被统一调用。
  6. 处理请求HandlerAdapter调用真正的Controller方法。方法内部执行业务逻辑(调用Service、DAO等),并返回一个ModelAndView或只是一个视图名称(如"success"),数据会被添加到Model中。
  7. 处理返回DispatcherServlet接收到ModelAndView或可解析的返回值。
  8. 解析视图DispatcherServlet调用ViewResolver,根据视图名称(如"success")解析出具体的View对象(如JstlView、ThymeleafView等)。
  9. 渲染视图DispatcherServlet将Model中的数据传递给View对象,调用其render()方法进行视图渲染(如填充HTML模板)。
  10. 返回响应:渲染完成后,生成最终的HTTP响应内容。
  11. 事后处理DispatcherServlet会触发InterceptorpostHandleafterCompletion方法,进行后续处理(如日志记录、资源清理等)。

第二部分:核心源码分析

让我们深入DispatcherServlet的源码,看看上述流程是如何实现的。核心方法是 doDispatch(HttpServletRequest request, HttpServletResponse response)

源码基于Spring Framework 5.x。代码有大量简化,只保留核心逻辑。

1. DispatcherServlet#doDispatch

这是处理请求的核心入口。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null; // 核心对象:处理执行链ModelAndView mv = null;// 1. 查找Handler:获取处理执行链mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {// 如果没有找到Handler,返回404noHandlerFound(processedRequest, response);return;}// 2. 获取HandlerAdapterHandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 3. 执行拦截器的preHandle方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {// 如果preHandle返回false,流程中断return;}// 4. ★ 核心:通过Adapter实际调用Handler(Controller方法)mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// 如果支持异步处理,逻辑会更复杂,这里省略...applyDefaultViewName(processedRequest, mv);// 5. 执行拦截器的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);// 6. 处理结果:渲染视图或处理异常processDispatchResult(processedRequest, response, mappedHandler, mv, null);
}
2. getHandler() - 查找HandlerExecutionChain
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {// 遍历所有注册的HandlerMappingfor (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler; // 找到就返回}}}return null;
}
  • HandlerMapping的实现类(如RequestMappingHandlerMapping)会根据请求的URL和@RequestMapping注解的信息,找到匹配的HandlerMethod(封装了Controller对象和Method对象)。
  • 同时,它也会查找所有匹配该请求的HandlerInterceptor,一并封装到HandlerExecutionChain中。
3. ha.handle() - HandlerAdapter调用Controller

以最常用的RequestMappingHandlerAdapter为例:

// 在RequestMappingHandlerAdapter中
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ServletWebRequest webRequest = new ServletWebRequest(request, response);WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);// 1. 创建一个Method对象的方法包装器,用于参数解析和方法调用ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);// 2. ★ 设置参数解析器:负责解析Controller方法的每个参数invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);// 3. ★ 设置返回值处理器:负责处理Controller方法的返回值invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);invocableMethod.setDataBinderFactory(binderFactory);// 4. 调用方法并处理返回值invocableMethod.invokeAndHandle(webRequest, mavContainer);// 5. 将结果封装成ModelAndView返回return getModelAndView(mavContainer, modelFactory, webRequest);
}
  • 参数解析器 (ArgumentResolver):根据参数注解(如@RequestParam, @RequestBody)和类型,从HttpServletRequest中提取数据并转换,然后注入到Controller方法的参数中。
  • 返回值处理器 (ReturnValueHandler):根据返回值的类型和注解(如@ResponseBody),决定如何处理返回值。是把它当做视图名称,还是直接写入响应体(JSON/XML)。
4. processDispatchResult() - 处理结果和渲染视图
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {// 处理异常(如果有的话,会转到渲染错误视图)if (exception != null) {mv = processHandlerException(request, response, mappedHandler.getHandler(), exception);}// 开始渲染视图if (mv != null && !mv.wasCleared()) {// ★ 核心:渲染视图render(mv, request, response);} else {// 没有视图,可能是@ResponseBody已经直接写回响应了}// 触发拦截器的afterCompletion方法if (mappedHandler != null) {mappedHandler.triggerAfterCompletion(request, response, null);}
}
5. render() - 渲染视图
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// 解析视图名称,得到View对象View view;String viewName = mv.getViewName();if (viewName != null) {// ★ 调用ViewResolver解析视图名称view = resolveViewName(viewName, mv.getModelInternal(), locale, request);} else {view = mv.getView(); // 如果ModelAndView里直接包含了View对象}// 调用View的render方法进行渲染view.render(mv.getModelInternal(), request, response);
}
  • ViewResolver(如InternalResourceViewResolver)会将视图名(如"user")解析为一个具体的View对象(如InternalResourceView,对应JSP)。
  • Viewrender()方法会完成最终的渲染工作,例如对于JSP,会将Model中的数据设置为request的属性,然后执行request.getRequestDispatcher("/WEB-INF/jsp/user.jsp").forward(request, response)

总结与关键点

  1. DispatcherServlet是大脑:它不干活,只负责调度。
  2. 组件协作:Spring MVC的强大之处在于其高度可配置的组件化设计。每个核心接口(HandlerMapping, HandlerAdapter, ViewResolver等)都有多种实现,你可以替换或扩展它们来实现自定义行为。
  3. 适配器模式是核心HandlerAdapter屏蔽了不同Handler类型的差异,使得框架极其灵活。
  4. 扩展性:通过HandlerInterceptor可以在请求处理的各个关键节点插入自定义逻辑(权限、日志等)。通过自定义ArgumentResolverReturnValueHandler可以处理任何类型的参数和返回值。

通过结合图解理解流程,再通过源码分析理解实现细节,你就能真正掌握Spring MVC的精髓。建议在IDE中打开Spring源码,沿着doDispatch方法一步步调试,会有更深刻的体会。

http://www.xdnf.cn/news/18721.html

相关文章:

  • Hibernate详解
  • 爆肝三周,我终于上线了自己的第一个小程序
  • Vue 项目 package.json 终极详解(主流实践 / 逐项说明)
  • 大型 C/C++ 项目中 AI 助手(Cursor / Claude Code)日常操作清单与发散思路
  • 详解triton.jit及PTX
  • 微服务-19.什么是网关
  • AI重塑跨境电商:选品成功率提升53%+物流效率加快34%,多语种运营成破局关键
  • 试析微剧《云端爱人》:AI时代的数字爱情寓言与情感觉醒
  • AI Agent与生成式AI双驱动:AI如何重塑商业格局并创造千亿级增量价值
  • Node【文件+模块化+对象】详讲:
  • 如何根据NTP协议报文的第一个字节来判断协议版本和处理模式?
  • 【CV】OpenCV①——OpenCV常用模块
  • 数学建模-线性规划(LP)
  • HbuilderX下载与安装
  • MATLAB GUI 设计入门:用 Guide 工具快速搭建交互界面
  • (LeetCode 每日一题) 1493. 删掉一个元素以后全为 1 的最长子数组 (双指针)
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(十八) 使用表格
  • 【分布式中间件】Kafka 核心配置深度解析与优化指南
  • 【数据结构与算法】并查集
  • 当GitHub“断网”:从应急到终极方案,手把手搭建永不宕机的代码协作体系
  • LLM 中增量解码与模型推理解读
  • 包装类 抽象类 内部类 接口
  • Flink Slot 不足导致任务Pending修复方案
  • VirtualBox 中安装 Ubuntu 22.04
  • 基于Java、GeoTools与PostGIS的对跖点求解研究
  • 如何快速对接印度股票市场数据API?完整开发指南
  • Solidity学习笔记
  • MATLAB实现CNN-GRU-Attention时序和空间特征结合-融合注意力机制混合神经网络模型的风速预测
  • AI Agent全栈开发流程推荐(全栈开发步骤)
  • Kubernetes v1.34 前瞻:资源管理、安全与可观测性的全面进化