Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中。 正式名称“Spring Web MVC”来自其源模块的名称(spring-webmvc),但它通常被称为“Spring MVC”。
与其他许多Web框架一样,Spring MVC围绕前端控制器模式进行设计,在该模式下,DispatcherServlet
作为中央Servlet
提供了用于请求处理的共享算法,而实际工作是由可配置的委托组件执行的。该模型非常灵活,并支持多种工作流程。
主体流程分析
DispatcherServlet
处理请求的核心逻辑入口为 doDispatch()
方法,下面是该方法及其部分依赖方法的实现
1 | protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { |
为子节约篇幅,对部分代码进行了删减,主要包括文件处理、异常处理、异步处理,这里只讨论普通的正常流程,整个流程可以分为如下几个步骤:
- 通过
HandlerMapping
获取当前请求的处理程序HandlerExecutionChain
。HandlerExecutionChain
是一个Facade
,由一个实际处理类与一组HandlerInterceptor
组成。实际处理类一般为HandlerMethod
,也可以是HttpRequestHandler
、Servlet
等; - 获取支持实际处理类对应的适配器
HandlerAdapter
,由于实际的处理类实现的方式有很多,这里使用适配器模式可以屏蔽掉实现类对调用逻辑的影响; - 调用拦截器的
preHandle()
方法 - 通过
HandlerAdapter
完成实际的业务逻辑处理 - 调用拦截器的
postHandle()
方法 - 使用
ViewResolver
解析视图并进行渲染 - 调用拦截器的
afterCompletion()
方法
整个调用流程的时序图如下:
常用扩展点
对于 SpringMVC,了解主体流程是远远不够的,一旦需要增加某些特性功能时,可能会很迷茫。比如:如何做全局的异常处理?如何对所有 Restful 请求进行日志记录?有可能你会说,我可以自定义一个切面进行拦截。那你是不是要新定义一套规范,让所有人按照既定规范来实现?还是说定义一个注解,每个接口自行标注?无论哪种实现都显得太复杂,不够优雅。实际上,如果你了解 SpringMVC 请求流程中预留的扩展点,这些问题都非常简单。
HandlerInterceptor
HandlerInterceptor
基本上类似于Servlet过滤器,但与后者相比,它仅允许自定义预处理以及禁止执行处理程序本身和自定义后处理的选项。通常用作授权检测,具体的触发节点在上述主体流程中已明确指出,可自行参考。
1 | public interface HandlerInterceptor { |
HandlerExceptionResolver
在 SpringMVC 处理请求映射或者实际调用 Controller
的过程中,如果发生异常,会将异常委托给一组 HandlerExceptionResolver
来处理,通常会给前端返回一个错误响应。
具体的代码实现在 DispatcherServlet
的 processHandlerException()
方法里面,逻辑如下:
1 | protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, |