Spring MVC 处理请求的流程
Spring MVC 处理请求的流程
- 流程步骤详解
- 第1步:发起请求 (HTTP Request)
- 第2步:映射处理器 (Handler Mapping)
- 第3步:获取适配器 (Handler Adapter)
- 第4步:执行拦截器前置处理 (Interceptors - preHandle)
- 第5步:真正调用处理器 (Handler Execution)
- 第6步:执行拦截器后置处理 (Interceptors - postHandle)
- 第7步:处理分发结果 (Process Dispatch Result)
- 第8步:执行拦截器完成处理 (Interceptors - afterCompletion)
- 第9步:返回响应 (HTTP Response)
- 核心组件总结
Spring MVC 处理请求的流程是其最核心的机制,理解它对于掌握整个框架至关重要。这个过程围绕一个核心——前端控制器模式(Front Controller Pattern),即 DispatcherServlet。
整个流程清晰且模块化,下图展示了从请求发起到响应返回的完整生命周期,以及其中涉及的核心组件交互:
流程步骤详解
现在,我们结合上图,对每一个步骤进行详细解读:
第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 的类型五花八门(如
@Controller
、HttpRequestHandler
、Servlet
)。DispatcherServlet
需要一個统一的接口来调用它们。HandlerAdapter
是适配器模式的典型应用,它屏蔽了不同处理器的调用细节。 - 常见实现:
RequestMappingHandlerAdapter
(用于适配@RequestMapping
注解的方法)。
第4步:执行拦截器前置处理 (Interceptors - preHandle)
在真正调用业务逻辑之前,DispatcherServlet
会调用 HandlerExecutionChain
中所有拦截器的 preHandle()
方法。
- 应用:进行权限检查、日志记录、 locale 解析等。
第5步:真正调用处理器 (Handler Execution)
现在,DispatcherServlet
让获取到的 HandlerAdapter
去真正地执行 Handler。
这个执行过程非常复杂,包括:
- 参数解析:根据方法签名,使用各种
HandlerMethodArgumentResolver
来解析方法的参数(如@RequestParam
,@RequestBody
,@PathVariable
)。 - 调用方法:通过反射调用控制器方法。
- 返回值处理:使用方法返回值,使用各种
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 的高度可配置性和可扩展性。其中的每一个步骤几乎都可以通过配置自定义组件或实现特定接口来进行干预和扩展。