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

一个 HTTP 请求进入 Spring MVC 应用后,大致经历了哪些主要步骤?

直接进入干货分享环节:假设我们的 Spring MVC 应用配置了 DispatcherServlet 作为前端控制器,并且映射路径为 /

  1. 请求到达 Web 容器 (如 Tomcat):

    • 客户端(例如浏览器)发送一个 HTTP 请求(比如 GET /myapp/users/123)。
    • Web 容器(Tomcat, Jetty 等)接收到这个请求。
  2. Web 容器路由到 DispatcherServlet:

    • Web 容器根据应用的部署描述符 (web.xml 或 Java Servlet 容器初始化器配置) 中 DispatcherServlet<servlet-mapping>(例如 //app/*),将该请求交给对应的 DispatcherServlet 实例处理。
  3. DispatcherServlet 接收请求:

    • DispatcherServlet 作为请求的统一入口点,开始处理该请求。
  4. 查找 Handler (处理器):

    • DispatcherServlet 查询其配置的所有 HandlerMapping 实现(按顺序)。
    • HandlerMapping 的任务是根据请求的信息(如 URL 路径 /users/123,HTTP 方法 GET 等)查找能够处理该请求的 Handler(通常是一个 Controller 类中的特定方法,封装为 HandlerMethod 对象)。
    • 如果找到合适的 Handler,HandlerMapping 会返回一个 HandlerExecutionChain 对象。这个对象不仅包含了找到的 Handler 本身,还包含了应用于该 Handler 的所有拦截器 (HandlerInterceptor) 列表。
    • 如果没有找到 Handler,通常会返回 404 Not Found 错误。
  5. 获取 HandlerAdapter (处理器适配器):

    • DispatcherServlet 拿到了 HandlerExecutionChain 后,需要调用其中的 Handler。但 Handler 的类型可能多种多样(例如基于注解的 HandlerMethod,旧式的实现了 Controller 接口的类等)。
    • 为了以统一的方式调用不同类型的 Handler,DispatcherServlet 会查询其配置的所有 HandlerAdapter 实现。
    • 它会找到支持当前 Handler 类型(例如 HandlerMethod)的那个 HandlerAdapter(例如 RequestMappingHandlerAdapter)。
  6. 执行拦截器的 preHandle 方法:

    • HandlerAdapter 在真正调用 Handler 方法之前,会按照 HandlerExecutionChain 中定义的顺序,依次调用所有拦截器的 preHandle(request, response, handler) 方法。
    • 这些拦截器可以执行一些预处理逻辑,如权限检查、日志记录等。
    • 如果任何一个 preHandle 方法返回 false,则请求处理流程在此中断,DispatcherServlet 会认为请求已被处理(拦截器可能直接生成了响应),然后会反向执行已执行过的拦截器的 afterCompletion 方法,然后结束。
  7. 调用 Handler (Controller 方法):

    • 如果所有拦截器的 preHandle 都返回 trueHandlerAdapter 就会调用 Handler(即 Controller 方法)。
    • 在调用之前,HandlerAdapter 内部会利用 HandlerMethodArgumentResolver 来解析 Controller 方法的参数。这包括:
      • 从请求中提取数据(如 @RequestParam, @PathVariable, @RequestBody 等)。
      • 进行数据绑定(将请求参数映射到方法参数对象)。
      • 进行数据类型转换。
      • 执行数据校验(如果使用了 @Valid 等)。
    • Controller 方法执行应用程序的核心业务逻辑,可能会调用 Service 层、与数据库交互等。
  8. Handler 方法返回结果:

    • Controller 方法执行完毕后会返回一个结果。这个结果可能是:
      • ModelAndView 对象:包含了逻辑视图名和模型数据。
      • String:通常代表逻辑视图名。
      • void:表示 Controller 自己处理了响应(例如直接操作 HttpServletResponse)。
      • 一个普通对象 (POJO):如果方法或类上有 @ResponseBody 注解,这个对象会被序列化后写入响应体。
      • ResponseEntity:可以更精细地控制响应状态码、头和响应体。
      • 其他(如 Callable, DeferredResult 用于异步处理)。
  9. 执行拦截器的 postHandle 方法:

    • HandlerAdapter 在成功调用完 Handler 方法后(但在视图渲染之前),会按照 HandlerExecutionChain 中定义的逆序,依次调用所有拦截器的 postHandle(request, response, handler, modelAndView) 方法。
    • 这些拦截器可以修改 ModelAndView 对象(例如添加一些公共的模型属性)或执行其他后处理逻辑。
    • 注意: 如果 Handler 方法执行过程中抛出了异常,postHandle 方法不会被执行。
  10. 处理 Handler 结果 / 视图解析 (如果需要):

    • DispatcherServlet 接收 HandlerAdapter 返回的结果。
    • 如果结果是 ModelAndView 或 String (逻辑视图名):
      • DispatcherServlet 会查询所有配置的 ViewResolver 实现(按顺序)。
      • ViewResolver 根据逻辑视图名解析得到一个具体的 View 接口的实例(如 JstlView, ThymeleafView)。这个 View 对象知道如何渲染特定的视图技术(如 JSP, Thymeleaf)。
    • 如果结果是 @ResponseBodyResponseEntity:
      • 这个步骤会被跳过。结果会直接交给后续步骤进行响应体写入。
  11. 视图渲染 (如果需要):

    • 如果上一步解析得到了 View 实例,DispatcherServlet 会调用该 View 实例的 render(model, request, response) 方法。
    • View 会使用传递过来的模型数据 (Model) 来渲染最终的输出(例如,JSP 引擎执行 JSP 文件生成 HTML)。
    • 渲染结果会被写入 HttpServletResponse 的输出流。
  12. 响应体写入 (对于 @ResponseBody / ResponseEntity):

    • 如果 Controller 返回的是需要直接写入响应体的对象 (@ResponseBodyResponseEntity 的 Body),DispatcherServlet (或者说 HandlerAdapter 内部的 HandlerMethodReturnValueHandler) 会使用注册的 HttpMessageConverter (如 MappingJackson2HttpMessageConverter) 将该对象序列化(例如转为 JSON 字符串)并写入 HttpServletResponse 的输出流。
  13. 执行拦截器的 afterCompletion 方法:

    • 无论请求处理是否成功(即无论是否发生异常,只要对应的 preHandle 返回了 true),在视图渲染完成或响应体写入完成后,DispatcherServlet 都会按照 HandlerExecutionChain 中定义的逆序,依次调用所有拦截器的 afterCompletion(request, response, handler, ex) 方法。
    • 这个方法通常用于资源清理工作(例如释放某些资源)。参数 ex 会包含处理过程中发生的异常(如果没有异常则为 null)。
  14. 异常处理:

    • 如果在上述任何步骤(除了拦截器的 preHandle 返回 false 之后)发生了异常,DispatcherServlet 会捕获这个异常。
    • 它会查询所有配置的 HandlerExceptionResolver 实现,找到能够处理该异常的 Resolver。
    • HandlerExceptionResolver 会处理异常,可能会将用户导向一个错误页面,或者返回一个包含错误信息的特定响应(例如 JSON 格式的错误信息)。
  15. 响应返回给客户端:

    • DispatcherServlet 将最终的 HTTP 响应(包含状态码、头信息、响应体)通过 Web 容器返回给客户端。

这个流程虽然看起来复杂,但每个组件职责清晰,使得 Spring MVC 框架非常灵活和可扩展。DispatcherServlet 在其中扮演了至关重要的中央协调者角色。

相关文章:

  • 电商平台数据采集与 QPS 计算全流程解析
  • 逻辑思维与软件开发:从选定方向到风险管理的全流程
  • Linux DRM显示驱动框架技术总结
  • 进阶篇 第 5 篇:现代预测方法 - Prophet 与机器学习特征工程
  • 今日CSS笔记
  • SAS宏调试:高效定位与解决典型问题
  • WLAN 漫游技术全解析:类型、转发模式与应用场景
  • 深度学习--卷积神经网络数据增强
  • 【Linux网络】构建基于UDP的简单聊天室系统
  • python入门简介
  • 课时一 平面机构的自由度与速度分析(上)
  • c语言修炼秘籍 - - 禁(进)忌(阶)秘(技)术(巧)【第七式】程序的编译
  • 生产环境大数据平台权限管理
  • python数据分析(二):Python Pandas索引技术详解
  • 7.6 GitHub Sentinel后端API实战:FastAPI高效集成与性能优化全解析
  • MuJoCo中的机器人状态获取
  • 【教程】安装 iterm2 打造漂亮且高性能的 mac 终端
  • 含锡废水具有显著的回收价值
  • 2024年ESWA SCI1区TOP:量子计算蜣螂算法QHDBO,深度解析+性能实测
  • 爬虫学习——下载文件和图片、模拟登录方式进行信息获取
  • 巴勒斯坦民族权力机构主席:哈马斯必须移交武器
  • 马上评丨冒名顶替上中专,为何一瞒就是30多年?
  • 张又侠董军分别与印尼国防部长会见会谈
  • 金发科技去年净利增160%,机器人等新领域催生材料新需求
  • 董明珠连任格力电器董事,回应管理层年轻化
  • 外交部:中方近日派出停火监督组赴缅,监督缅军和果敢同盟军停火