Spring MVC 处理请求的流程

Spring MVC 处理请求的流程

Spring MVC 处理请求的流程是其最核心的机制,理解它对于掌握整个框架至关重要。这个过程围绕一个核心------前端控制器模式(Front Controller Pattern),即 DispatcherServlet。

整个流程清晰且模块化,下图展示了从请求发起到响应返回的完整生命周期,以及其中涉及的核心组件交互:
Client DispatcherServlet (前端控制器) HandlerMapping HandlerAdapter Controller (@Controller) ViewResolver View (JSP/Thymeleaf...) HTTP Request 1. 接收请求 查询Handler 2. 映射查找 根据URL找到目标Controller和方法 返回HandlerExecutionChain (包含Handler和Interceptors) 3. 适配调用 获取HandlerAdapter 返回Adapter 按顺序执行preHandle() loop [4. 执行拦截器 (preHandle)] 5. 处理请求 (参数解析、方法调用、返回值处理) 调用Controller方法 返回方法执行结果(ModelAndView/String等) 逆序执行postHandle() loop [6. 执行拦截器 (postHandle)] 7. 处理视图/响应 通过HttpMessageConverter直接写回响应 解析视图名 返回View对象 调用render()渲染视图 返回渲染后的HTML alt [返回@ResponseBody] [返回视图名] 最终触发afterCompletion() loop [8. 执行拦截器 (afterCompletion)] 9. 返回响应 HTTP Response Client DispatcherServlet (前端控制器) HandlerMapping HandlerAdapter Controller (@Controller) ViewResolver View (JSP/Thymeleaf...)


流程步骤详解

现在,我们结合上图,对每一个步骤进行详细解读:

第1步:发起请求 (HTTP Request)

请求离开浏览器,到达 DispatcherServlet。根据 web.xml 或 Servlet 3.0+ 的配置,所有匹配特定模式(如 /)的请求都会由它处理。

第2步:映射处理器 (Handler Mapping)

DispatcherServlet 咨询一个或多个 HandlerMapping Bean:"这个请求应该由哪个'处理器'(Handler)来处理?"。HandlerMapping 根据请求的 URL 进行查找。

  • 常见实现
    • RequestMappingHandlerMapping:用于映射 @RequestMapping 注解的方法(最常用)。
    • BeanNameUrlHandlerMapping:根据 Bean 的名字进行映射。
  • 返回结果 :不仅返回找到的目标处理器方法 ,还会返回一个 HandlerExecutionChain 对象,该对象包含了找到的 Handler 以及所有适用于该请求的 HandlerInterceptor(拦截器)。
第3步:获取适配器 (Handler Adapter)

DispatcherServlet 拿着找到的 Handler,问一堆 HandlerAdapter:"你们谁支持(support)这个 Handler 的类型?"

  • 为什么需要它? :Handler 的类型五花八门(如 @ControllerHttpRequestHandlerServlet)。DispatcherServlet 需要一個统一的接口来调用它们。HandlerAdapter适配器模式的典型应用,它屏蔽了不同处理器的调用细节。
  • 常见实现RequestMappingHandlerAdapter(用于适配 @RequestMapping 注解的方法)。
第4步:执行拦截器前置处理 (Interceptors - preHandle)

在真正调用业务逻辑之前,DispatcherServlet 会调用 HandlerExecutionChain 中所有拦截器的 preHandle() 方法。

  • 应用:进行权限检查、日志记录、 locale 解析等。
第5步:真正调用处理器 (Handler Execution)

现在,DispatcherServlet 让获取到的 HandlerAdapter 去真正地执行 Handler。

这个执行过程非常复杂,包括:

  1. 参数解析 :根据方法签名,使用各种 HandlerMethodArgumentResolver 来解析方法的参数(如 @RequestParam, @RequestBody, @PathVariable)。
  2. 调用方法:通过反射调用控制器方法。
  3. 返回值处理 :使用方法返回值,使用各种 HandlerMethodReturnValueHandler 处理返回值(如 @ResponseBody, ModelAndView)。
第6步:执行拦截器后置处理 (Interceptors - postHandle)

控制器方法执行完毕后,DispatcherServlet逆序 调用所有拦截器的 postHandle() 方法。

  • 应用 :有机会修改即将发送到视图的 ModelAndView 对象。
第7步:处理分发结果 (Process Dispatch Result)

这是视图渲染和响应的核心环节。DispatcherServlet 根据控制器方法的返回结果,进行不同的处理:

  • 情况A:方法有 @ResponseBody 或返回 ResponseEntity
    • 流程RequestResponseBodyMethodProcessor 会使用配置的 HttpMessageConverter(如 MappingJackson2HttpMessageConverter)将返回值(如一个 Java 对象)直接序列化 (如转为 JSON),并写入 HttpServletResponse 的输出流。此过程不涉及视图解析。
  • 情况B:方法返回视图名(如 String)或 ModelAndView
    • 视图解析DispatcherServlet 调用 ViewResolver 来根据逻辑视图名(如 "success")解析为一个具体的 View 对象(如 InternalResourceView 对应 JSP,ThymeleafView 对应 Thymeleaf)。
    • 视图渲染DispatcherServlet 将模型数据传递给 View 对象,并调用其 render() 方法。该方法会生成最终的 HTML 内容(如合并 JSP 模板和模型数据),并将其写入 HttpServletResponse 的输出流。
第8步:执行拦截器完成处理 (Interceptors - afterCompletion)

无论请求处理成功还是出现异常,DispatcherServlet 都会最终触发所有拦截器的 afterCompletion() 方法。

  • 应用:进行资源清理、记录请求完成时间等。
第9步:返回响应 (HTTP Response)

最终,完整的响应通过 Servlet 容器(如 Tomcat)返回给客户端。


核心组件总结

组件 职责 类比
DispatcherServlet 前端控制器,协调所有组件,是整个流程的总指挥。 餐厅的前台经理
HandlerMapping 请求映射,根据 URL 找到对应的处理器。 餐厅的引座员
HandlerAdapter 处理器适配,用统一的接口调用各种不同类型的处理器。 餐厅的服务员,连接经理和后厨
Handler 处理器 (通常是我们写的 @Controller)。 餐厅的厨师
ViewResolver 视图解析器,将逻辑视图名解析为具体视图对象。 餐厅的出菜员
View 视图,负责将模型数据渲染成最终的响应内容(HTML/JSON等)。 最终呈现的菜肴
HandlerInterceptor 拦截器,在请求处理的不同阶段进行横切处理。 餐厅的质检员

这个流程充分体现了 Spring MVC 的高度可配置性和可扩展性。其中的每一个步骤几乎都可以通过配置自定义组件或实现特定接口来进行干预和扩展。

相关推荐
小扳6 小时前
SpringBootWeb 篇-深入了解 ThreadLocal 存在内存泄漏问题
java·开发语言·spring boot·面试
lxsy6 小时前
spring-ai-alibaba-deepresearch 学习(十三)——ResearcherNode
java·源码分析·deepresearch·ai-alibaba
ShineWinsu6 小时前
对于单链表相关经典算法题:206. 反转链表及876. 链表的中间结点的解析
java·c语言·数据结构·学习·算法·链表·力扣
迦蓝叶6 小时前
JAiRouter 配置文件重构纪实 ——基于单一职责原则的模块化拆分与内聚性提升
java·网关·ai·重构·openai·prometheus·单一职责原则
ST.J6 小时前
系统架构思考20241204
java·笔记·系统架构
TDengine (老段)7 小时前
TDengine 时间函数 TIMETRUNCATE 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
给我个面子中不7 小时前
JUC、JVM八股补充
java·开发语言·jvm
mask哥8 小时前
详解flink性能优化
java·大数据·微服务·性能优化·flink·kafka·stream
hqxstudying8 小时前
Kafka 深入研究:从架构革新到性能优化的全面解析
java·开发语言·微服务·kafka·springcloud