Skip to content

请求处理流程 (Processing)

DispatcherServlet 处理请求的具体流程如下:

  1. 绑定上下文:在请求中搜索并绑定 WebApplicationContext 作为属性,以便控制器和流程中的其他元素可以使用它。默认情况下,它绑定在 DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE 键下。
  2. 绑定区域解析器:将区域解析器(Locale Resolver)绑定到请求,以允许流程中的元素解析在处理请求(渲染视图、准备数据等)时要使用的区域。如果你不需要区域解析,则不需要配置它。
  3. 多部分请求处理:如果指定了多部分文件解析器(Multipart Resolver),则会检查请求是否包含多部分内容。如果发现多部分内容,请求将被包装在 MultipartHttpServletRequest 中,以便流程中的其他元素进一步处理。
  4. 查找处理器:搜索合适的处理器(Handler)。如果找到了处理器,则执行与该处理器关联的执行链(包括预处理器、后处理器和控制器),以准备用于渲染的模型(Model)。对于注解控制器,响应也可以直接在 HandlerAdapter 内部渲染,而不是返回视图。
  5. 视图渲染:如果返回了模型,则进行视图渲染。如果没有返回模型(可能是由于预处理器或后处理器出于安全等原因拦截了请求),则不会渲染视图,因为请求可能已经完成。

异常处理与缓存

  • 异常处理:在 WebApplicationContext 中声明的 HandlerExceptionResolver Bean 用于解析请求处理过程中抛出的异常。这些异常解析器允许自定义处理异常的逻辑。
  • HTTP 缓存支持:处理器可以使用 WebRequestcheckNotModified 方法,以及针对注解控制器的其他选项(如 ETag 和 Last-Modified 支持)。

初始化参数

你可以通过在 web.xml 文件中的 Servlet 声明中添加 Servlet 初始化参数(init-param 元素)来定制单个 DispatcherServlet 实例。支持的参数如下:

参数说明
contextClass实现 ConfigurableWebApplicationContext 的类,由该 Servlet 实例化并进行本地配置。默认使用 XmlWebApplicationContext
contextConfigLocation传递给上下文实例(由 contextClass 指定)的字符串,指示可以找到上下文的位置。该字符串可以包含多个路径(使用逗号作为分隔符)。如果多个路径中有重复定义的 Bean,则以后者为准。
namespaceWebApplicationContext 的命名空间。默认为 [servlet-name]-servlet
throwExceptionIfNoHandlerFound当没找到处理请求的处理器时,是否抛出 NoHandlerFoundException。该异常可以被 HandlerExceptionResolver 捕获并处理。从 6.1 版本起,该属性默认为 true 且已弃用。

补充教学

1. 为什么“执行链 (Execution Chain)”如此关键?

很多人认为 DispatcherServlet 只是调用 Controller。实际上,它返回的是一个 HandlerExecutionChain 对象。

  • 组成部分:它包含一个真正的 处理器 (Handler) 和一组 拦截器 (Interceptors)
  • 运行逻辑
    1. 执行所有拦截器的 preHandle 方法。
    2. 执行 Controller 方法。
    3. 执行所有拦截器的 postHandle 方法。
    4. 视图渲染。
    5. 执行所有拦截器的 afterCompletion 方法。 这种流水线设计让 Spring MVC 能够非侵入式地处理权限、日志、事务等横切关注点。

2. 多部分请求的“二次包装”

当你的应用需要处理文件上传时,MultipartResolver 会检查 HTTP 请求头中的 Content-Type 是否为 multipart/form-data

  • 如果是:它会将原始的 HttpServletRequest 包装成 MultipartHttpServletRequest
  • 好处:这个新对象提供了 getFile(String name) 这样方便的 API。在你的 Controller 中,你可以直接申明 MultipartFile 类型的参数,Spring 会自动从这个包装类中提取文件数据。

3. 理解 checkNotModified 的性能优化

这是一个经常被忽略的性能杀手锏:

  • 工作机制:当浏览器带上 If-Modified-SinceIf-None-Match 头时,你的 Controller 可以先查一下数据库数据的最后修改时间或指纹(ETag)。
  • 效果:如果数据没变,调用 webRequest.checkNotModified(timestamp) 会立即返回 true。此时 Spring 会直接返回 304 Not Modified 响应,正文为空,完全跳过繁重的视图渲染和数据传输过程。这能极大节省带宽。

Based on Spring Framework.