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

图解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.dtcms.com/a/348913.html

相关文章:

  • response对象的elapsed属性
  • 深度模块化剖析:构建一个健壮的、支持动态Cookie和代理的Python网络爬虫
  • Altium Designer 22使用笔记(9)---PCB布局、布线操作
  • halcon(一)一维码解码
  • 普元低代码开发平台:开启企业高效创新新征程
  • 刷题日记0824
  • 【AI论文】实习生-S1:一种科学多模态基础模型
  • 0824 MLIR和AST相关资料
  • 复杂工业场景识别率↑18.3%!陌讯多模态OCR算法实战解析
  • 虚幻引擎5(UE5)Android端游戏开发全流程指南:从环境配置到项目发布
  • Qt工具栏中图标槽函数没有响应的问题分析
  • 【JVM内存结构系列】三、堆内存深度解析:Java对象的“生存主场”
  • 【数据分享】地级市能源利用效率(超效率SBM、超效率CCR)(2006-2023)
  • Vue中 this.$emit() 方法详解, 帮助子组件向父组件传递事件
  • 纯血鸿蒙下的webdav库
  • vue中 computed vs methods
  • 【C++闯关笔记】STL:string的学习和使用(万字精讲)
  • 开发软件安装记录
  • Kubernetes v1.34 前瞻:资源管理、安全与可观测性的全面进化
  • golang6 条件循环
  • R语言rbind()和cbind()使用
  • 信贷策略域——信贷产品策略设计
  • 【数据结构】排序算法全解析
  • 【链表 - LeetCode】206. 反转链表【带ACM调试】
  • HTTP URL 详解:互联网资源的精准地址
  • 当AI遇上终端:Gemini CLI的技术魔法与架构奥秘
  • 在 vue3 和 vue2 中,computed 计算属性和 methods 方法区别是什么
  • 打响“A+H”双重上市突围战,云天励飞实力如何?
  • JUC并发编程07 - wait-ify/park-un/安全分析
  • 《CF1120D Power Tree》