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

Spring MVC 请求执行流程详解

1. 核心组件简介

在深入了解流程之前,首先需要认识流程中涉及的核心组件:

  • DispatcherServlet前端控制器(Front Controller),是整个流程的核心和入口。它接收所有请求,并负责协调各个组件共同完成请求处理,但其自身不处理业务逻辑。
  • HandlerMapping处理器映射器,根据请求的 URL、方法等信息,找到能够处理该请求的处理器(Handler)拦截器(Interceptors)
  • HandlerAdapter处理器适配器,负责以统一的接口方式去实际执行找到的处理器(如 @Controller 中的方法)。因为处理器有多种形式(如基于注解的控制器、实现 Controller 接口的控制器等),适配器模式使得 DispatcherServlet 无需关心处理器的具体实现。
  • HandlerInterceptor处理器拦截器,提供了在处理器执行前、后以及请求完成后的拦截钩子,用于实现横切关注点(如日志、权限验证等)。
  • Handler处理器,通常是我们编写的带有 @Controller@RestController 注解的类中的方法,是实际执行业务逻辑的地方。
  • ViewResolver视图解析器,根据控制器返回的逻辑视图名(如 "home"),解析出具体的 View 对象(如 JSP, Thymeleaf 模板等)。
  • View视图,负责将模型数据渲染成最终的响应内容(如 HTML 页面)。
  • HandlerExceptionResolver异常解析器,负责处理请求处理过程中抛出的异常,将其转换为统一的错误响应(如错误页面、JSON 错误信息)。
  • MultipartResolver: ** multipart 解析器**,用于解析文件上传等 multipart 类型的请求。

2. 请求执行流程详述

一个典型的 HTTP 请求在 Spring MVC 中的处理遵循一条清晰的“请求-响应”管道。其完整流程如下图所示:
在这里插入图片描述

阶段一:请求接收与分发

  1. 用户发起请求: 用户通过浏览器访问一个 URL(例如 http://example.com/app/products)。
  2. 请求到达 DispatcherServlet
    • HTTP 请求首先被 Web 容器(如 Tomcat)捕获。
    • 根据 web.xmlServletRegistrationBean 中的配置,匹配到请求路径的 DispatcherServlet 开始处理该请求。
    • DispatcherServlet 是唯一的入口,它代表“前端控制器”设计模式。

阶段二:寻找处理器

  1. 查询处理器映射(HandlerMapping
    • DispatcherServlet 会查询所有配置的 HandlerMapping bean(如 RequestMappingHandlerMapping),询问哪一个 Handler(控制器方法)能处理当前请求。
    • HandlerMapping 根据请求的 URL、HTTP 方法(GET、POST等)、请求头等信息进行匹配。
    • 如果找到匹配的处理器,HandlerMapping 会返回一个 HandlerExecutionChain 对象。该对象不仅包含了目标处理器(Handler),还包含了适用于该请求的所有 HandlerInterceptor(拦截器)。

阶段三:执行预处理拦截器

  1. 执行拦截器的 preHandle 方法
    • DispatcherServlet 按顺序执行 HandlerExecutionChain 中所有拦截器的 preHandle() 方法。
    • 拦截器通常用于执行权限检查、日志记录、本地化设置等预处理逻辑。
    • 重要: 如果任何一个拦截器的 preHandle 方法返回 false,则流程中断,直接返回,不会执行后续的处理器和拦截器。

阶段四:执行处理器(业务逻辑)

  1. 获取并调用处理器适配器(HandlerAdapter
    • DispatcherServlet 遍历所有配置的 HandlerAdapter,找到第一个支持该类型处理器的适配器(如 RequestMappingHandlerAdapter 用于支持 @RequestMapping 注解的方法)。
  2. 实际执行处理器
    • 适配器调用处理器的具体方法(即我们编写的 @Controller 中的方法),并传入相应的参数(如 @RequestParam, @PathVariable, @RequestBody 等注解修饰的参数)。参数解析由一系列的 HandlerMethodArgumentResolver 完成。
    • 处理器执行业务逻辑(如调用 Service 层),并返回一个结果。这个结果通常被包装成一个 ModelAndView 对象(包含模型数据和视图名),或者只是一个视图名,或者是一个被 @ResponseBody 注解的对象。

阶段五:执行后处理拦截器

  1. 执行拦截器的 postHandle 方法
    • 处理器执行完毕后,DispatcherServlet逆序执行所有拦截器的 postHandle() 方法。
    • 此时可以对 ModelAndView 进行进一步的修改(如添加公共模型数据),但在前后端分离架构中(返回 JSON),此方法可能用处不大。

阶段六:处理结果与渲染视图

  1. 处理返回结果

    • 如果处理器方法返回的是 String(视图名)或 ModelAndViewDispatcherServlet 会将其转发给 ViewResolver
    • ViewResolver 根据逻辑视图名解析出具体的 View 对象(例如,将 "products" 解析为 /WEB-INF/views/products.jsp)。
    • 如果方法有 @ResponseBody 注解或控制器有 @RestController 注解,则结果会通过 HttpMessageConverter 直接写入 HTTP 响应体(返回 JSON/XML 等),跳过后面的视图渲染步骤。
  2. 渲染视图(如果需要)

    • DispatcherServlet 将模型数据传递给解析得到的 View 对象,并调用其 render() 方法。
    • View 负责将模型数据与模板结合,生成最终的响应内容(如 HTML)。

阶段七:请求完成回调

  1. 执行拦截器的 afterCompletion 方法
    • 无论请求处理成功与否,在返回响应给客户端之前DispatcherServlet 会按逆序执行所有拦截器的 afterCompletion() 方法。
    • 此方法非常适合进行资源清理、记录请求完成日志等操作。注意:即使前面的 preHandle 或处理器执行过程中抛出异常,此方法也会被调用(但仅限那些 preHandle 成功执行并返回 true 的拦截器)。

阶段八:返回响应

  1. 返回响应: 最终生成的响应(可能是 HTML 页面,也可能是 JSON 数据)通过 DispatcherServlet 返回给 Web 容器,并由容器最终发送回客户端。

4. 异常处理机制

异常处理贯穿于上述流程的多个环节:

  • 处理器执行期间: 如果在任何阶段(特别是处理器执行时)抛出异常,DispatcherServlet 会捕获它。
  • 委托给 HandlerExceptionResolverDispatcherServlet 会遍历所有配置的 HandlerExceptionResolver(如 @ExceptionHandler, ExceptionHandlerExceptionResolver),让它们来处理异常。
  • 解析异常: 异常解析器可能会将异常转换为一个错误响应(如设置特定的 HTTP 状态码,返回一个错误视图 ModelAndView("error"),或者直接写入一个 JSON 错误信息)。
  • 跳过后续步骤: 一旦发生异常,正常的流程(如 postHandle)会被跳过,但 afterCompletion 仍然会执行。

5. 总结与要点

  • 中心化控制DispatcherServlet 是流程的绝对核心,是所有请求的交通枢纽。
  • 职责分离: 每个组件职责单一(映射、适配、执行、解析),符合设计模式的开闭原则,使得框架高度可配置和可扩展。
  • 扩展点: 开发者可以通过实现或扩展 HandlerInterceptor, HandlerAdapter, ViewResolver, HandlerExceptionResolver 等接口来定制流程的特定环节。
  • 两种主要结果处理方式
    1. 传统 MVC: 处理器返回视图名 -> ViewResolver 解析 -> View 渲染。
    2. RESTful API: 处理器返回数据 + @ResponseBody -> HttpMessageConverter 转换 -> 直接写入响应。
http://www.dtcms.com/a/398041.html

相关文章:

  • 德州网站推广尚义网站建设
  • 麒麟 Linux|深入解析 Linux 文件系统架构:理念、结构与工作机制
  • 编程语言综合教程:Java、Python、C++、Go 全面解析
  • 第三部分:VTK过滤器类详解(第58章 图像处理过滤器类)
  • 瑞芯微RK35XX系列Linux实时性详细测试对比( PREEMPT_RT和Xenomai )
  • 虚拟机ubuntu用wifi adb 调试手机
  • 解决慢SQL问题
  • OpenEuler安装mysql二进制版本
  • 【ADB】常用按键代码:adb的所有模拟按键
  • 网站制作基础教程外贸公司开办流程
  • 山亭建设局网站翻译网页
  • 坂田做网站的公司听小说的网站哪个好
  • CNN-Transformer:PyTorch遥感【含无人机】影像的分类、检测、语义分割和点云分类
  • RAG知识库构建
  • MinMaxScaler Scikit-learn sparkml 稀疏向量
  • 基于WPF实现打印机连接与打印功能
  • 储能材料:弹性势能储能及材料技术突破
  • RapidJSON 自定义内存分配器详解与实战
  • 深度学习-PyTorch 模型
  • WPF依赖属性学习
  • 云原生-高级阶段-利用rsync备份全网服务器数据
  • wordpress建购物网站抚顺营销型网站建设
  • Pythoner 的Flask项目实践-添加Shapefile面数据并展示功能Mapboxgl底图
  • Flutter混合Android开发Release 打包失败GeneratedPluginRegistrant.java,Plugin不存在
  • docker 安装TDengine 并创建新用户
  • 网站推广实施方案珠海网站制作软件
  • 为世界添彩 - WebGL 中的颜色与着色器变量
  • 初识MYSQL —— mysql的安装
  • c回顾 01
  • 【LeetCode 每日一题】3484. 设计电子表格——(解法一)二维数组