bigywater.tech
Spring · 39

DispatcherServlet:一个请求的完整路径

一个 HTTP 请求进到 Spring MVC 之后到底经过哪些环节?Filter、Interceptor、参数解析、返回值处理各在什么时候?抛异常和 404、405 又是怎么走的?这篇用 Spring Boot 4.0.8 的 Spring MVC 7.0.9,把每个扩展点的调用顺序逐个记下来。

29 个
RequestMappingHandlerAdapter 的参数解析器个数(返回值处理器 15 个,消息转换器 6 个)
0 次
GET /only-post(405)在第一遍里 Interceptor.preHandle 被调用的次数
ResourceHttpRequestHandler
GET /nope 的 404 实际上由静态资源处理器兜底处理

组件

实测 · 本机执行输出
  DispatcherServlet 是容器里的一个 Bean:DispatcherServlet;参数 detectAllHandlerMappings 默认由 Spring 决定
  HandlerMapping(按顺序):[RouterFunctionMapping, RequestMappingHandlerMapping, WelcomePageHandlerMapping, BeanNameUrlHandlerMapping, WelcomePageNotAcceptableHandlerMapping, SimpleUrlHandlerMapping]
  HandlerAdapter(按顺序):[RequestMappingHandlerAdapter, HandlerFunctionAdapter, HttpRequestHandlerAdapter, SimpleControllerHandlerAdapter]
  HandlerExceptionResolver(按顺序):[DefaultErrorAttributes, HandlerExceptionResolverComposite]
  RequestMappingHandlerAdapter 的参数解析器 29 个,返回值处理器 15 个,消息转换器 6 个:[ByteArray, String, Resource, ResourceRegion, AllEncompassingForm, JacksonJson]
  RequestMappingHandlerMapping 登记的处理方法 5 个(含 Boot 自带的 /error):[{ [/error], produces [text/html]}, { [/error]}, {GET [/boom]}, {GET [/hello/{name}]}, {POST [/only-post]}]

DispatcherServlet 背后有 6 个 HandlerMapping、4 个 HandlerAdapter 和一长串解析器。

成功路径

实测 · 本机执行输出
  响应:200 {"hi":"spring"}
  ① Filter 进入 GET /hello/spring
  ③ Interceptor.preHandle,handler 类型 = HandlerMethod(hello)
  ④ 自定义 HandlerMethodArgumentResolver 解析 Trace 参数
        Controller 方法 hello(spring,Trace[id=t-1])
  ⑥ ResponseBodyAdvice.beforeBodyWrite,将用 JacksonJsonHttpMessageConverter 写出
  ⑧ Interceptor.postHandle
  ⑨ Interceptor.afterCompletion,异常 = 无
  ⑩ Filter 返回,状态码 200

Filter 包住拦截器,拦截器包住控制器方法,返回值经过 ResponseBodyAdvice 和消息转换器写出。

异常路径

实测 · 本机执行输出
  响应:500 handled
  ① Filter 进入 GET /boom
  ③ Interceptor.preHandle,handler 类型 = HandlerMethod(boom)
  ⑦′ @ExceptionHandler 处理 IllegalStateException
  ⑥ ResponseBodyAdvice.beforeBodyWrite,将用 StringHttpMessageConverter 写出
  ⑨ Interceptor.afterCompletion,异常 = 无
  ⑩ Filter 返回,状态码 500

异常由 @ExceptionHandler 处理,没有 postHandle,afterCompletion 照常调用。

404 与 405

实测 · 本机执行输出
  GET /nope → 404:① Filter 进入 GET /nope | ③ Interceptor.preHandle,handler 类型 = ResourceHttpRequestHandler | ⑨ Interceptor.afterCompletion,异常 = 无 | ⑩ Filter 返回,状态码 404 | ③ Interceptor.preHandle,handler 类型 = HandlerMethod(error) | ⑥ ResponseBodyAdvice.beforeBodyWrite,将用 JacksonJsonHttpMessageConverter 写出 | ⑧ Interceptor.postHandle | ⑨ Interceptor.afterCompletion,异常 = 无
  GET /only-post → 405:① Filter 进入 GET /only-post | ⑩ Filter 返回,状态码 405 | ③ Interceptor.preHandle,handler 类型 = HandlerMethod(error) | ⑥ ResponseBodyAdvice.beforeBodyWrite,将用 JacksonJsonHttpMessageConverter 写出 | ⑧ Interceptor.postHandle | ⑨ Interceptor.afterCompletion,异常 = 无

404 由静态资源处理器兜底再转 /error,405 没有处理器,拦截器在错误派发里再走一遍。

分步演示

DispatcherServlet 的请求路径
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。用 Spring Boot 4.0.8 的 SpringApplication(spring-boot-starter-webmvc,内嵌 Tomcat 11),事件由 Filter、HandlerInterceptor、HandlerMethodArgumentResolver、ResponseBodyAdvice、@ExceptionHandler 这些公开扩展点打印,所以 HandlerMapping 查找、HandlerAdapter 选择这些没有回调的环节在时间线里看不到
    • 没有验证:异步请求(DeferredResult / Callable)的 Interceptor 调用次数(见后面的异步请求篇);multipart 请求;ViewResolver 与模板引擎路径(这里只测了 @RestController);HandlerMapping 的 Order 值本身;WebMvcConfigurer 之外直接重写 DispatcherServlet 的做法
    京ICP备2026067502号-1京公网安备11010502063487号