Spring MVC:DispatcherServlet

在 Spring MVC 中,有一个类是必定要去了解和熟悉的,这个类就是 DispatcherServlet,该类负责了 MVC 中最主要的内容——请求转发处理。 在本文中,我们会在源码级别讲述 DispatcherServlet 的运行机制和高度灵活的扩展性。

DispatcherServlet 的处理过程

DispatcherServlet 的处理过程更像是一个循环执行接口程序的过程,只是有几个相对独立的部分。如果使用 IDE 进行断点你会发现它的流程如下:
  1. doService
    1. 解析请求属性
  2. doDispatch
    1. getHandler( 请求到 Handler 对象映射 )
    2. getHanderAdapter
    3. preHandle
    4. handle
    5. postHandle
    6. processDispatchResult
      1. 完成异常解析
      2. render
        1. 区域处理
        2. 视图名解析
        3. 视图呈现
    7. afterCompletion

DispatcherServlet 的功能

DispatcherServlet 运行过程有以下几个大的功能板块:
  • 基于 JavaBeans 的方式进行配置
  • 控制 Handler 对象路由:HandlerMapping
  • Handler 适配处理:HandlerAdapter
  • 异常处理策略
  • 视图解析策略
  • 请求视图名转译
  • 复合表单内容处理
  • 区域解析
  • 主题解析
Java Beans 方式配置是 Java EE 中的一个规范,其定义 Java Beans 支持属性,事件和方法。如果你对 Java Beans 还不够熟悉可以查看 Oracle 对 Java Beans 是怎样编写的来了解具体的信息
HandlerMapping 负责了请求的路由,也就是说在接收到请求后,请求会经过它的处理最后返回 Handler 对象(可以是任意的类型)。其运行机制由两个组件组成:HandlerInterceptor 和 HandlerExecutionChain。HandlerInterceptor 有三个主要方法:preHandle(),postHandle(),afterCompletion()。
  • preHandle() 方法在 HandlerAdapter 发起调用 Handler 时触发。如果返回 true 表示会处理下一个 Interceptor,否则会认为以及处理完请求。
  • postHandle() 方法在 HandlerAdapter 调用 Handler 并且在 呈现视图 之前调用
  • afterCompletion() 仅在 preHandle() 方法返回 true 并且呈现视图之后执行
HandlerExcutionChain 类真正地组织 HandlerInterceptor 和 Handler 对象。并且真正在调用preHandle(),postHandle(),afterCompletion()。最后这个对象在 HandlerMapping 中 getHandler() 进行返回。
HandlerAdapter (适配器模式)负责完成 Handler 的实际处理。在 HandlerMapping 的处理结果的基础上,HandlerAdapter 表达了如何运作 Handler 对象,如 SimpleControllerHandlerAdapter 是针对 Controller 接口调用 Handler 对象的 handleRequest() 方法完成处理的。
异常处理由 HandlerExceptionResolver 负责,在流程 3-7 步中,如果抛出了异常会经由 processDispatchResult() 进行判断最后交由 processHandlerException() 进行检查异常解析结果,循环判断(最后一个
HandlerExceptionResolver 为第一个判断)有一个可以处理(判断 ModelAndView 返回值不为空)那么就会认为处理完成并把 ModelAndVIew 进行返回,间接使用 视图解析 的执行路径 。
视图解析,由 ViewResolver 负责,ViewResolver 会通过 viewName 获取到相应的 View 对象最后完成 ModelAndView 的呈现工作。与上面的做法先类似,都是使用循环的方式进行解析,一旦解析成功直接返回。 processDispatchResult() 负责调用 render() 方法呈现相应的页面结果。在 render() 方法中,地区解析是在这里完成的,它可以使用 Accept-Language 请求头来给 response 对象设置区域(Content-Language)响应头。最后通过 resolveViewName 获取到交由 View 对象进行实际的呈现工作。
请求视图名转译,通过请求获取相应的视图名,最后经过 ViewResolver 解析出相应的 View 对象,默认的转译类(DefaultRequestToViewNameTranslator)是把请求路径和资源名返回,如 http://localhost/a/b/c.html 将会返回 a/b/c

DispatchServlet 应用

  1. 自定义 HandlerIntercepter ,可以完成与 Handler 进行绑定的拦截处理,而不需要 AOP 编程
  2. 自定义 HandlerAdapter,可以实现自定义的 Handler 如实现一套不同的控制器处理逻辑
  3. 自定义 ViewResovler 视图解析,实现定制的 视图 呈现方式
  4. 自定义 HandlerExceptionResolver 异常处理,