Spring MVC DispatcherServlet分析
前言
Spring MVC是工作在Java Servlet之上的一套MVC框架,本文将通过分析Spring MVC的请求处理流程来学习Spring MVC的工作原理。
主要将分析:
- DispatcherServlet 控制请求处理全局流程
- HandlerMapping 控制请求到处理器的路由
- HandlerAdapter 用于适配任何处理器接口
- HandlerExceptionResolver 处理处理器异常
- ViewResolver 解析视图名称到视图对象
版本:Spring Framework 4.3.x
1.DispatcherServlet
DispatcherServlet是HTTP请求处理程序的中央调度器,它主要包括以下组件:
- HandlerMapping 多个,存在先后顺序
- HandlerAdapter 多个,存在先后顺序
- HandlerExceptionResolver 多个,存在先后顺序
- ViewResolver 多个,存在先后顺序
组件的注册
支持多个组件的组件类型,将从上下文中根据类型获取。对于单个组件类型,根据bean名称和类型获取实例。如果没有找到,使用默认配置。
请求的处理流程
首先遍历询问HandlerMapping
列表查找匹配的处理器,返回一个HandlerExecutionChain
。HandlerExecutionChain
包含了HandlerInterceptor
列表,并封装了处理器
对象。
如果未找到,设置404错误(通过sendError()),返回容器并处理错误。
然后遍历询问HandlerAdapter
列表查找匹配的适配器。如果没有找到,抛出异常。
通过适配器,处理器完成对请求的处理,并返回模型和视图。
如果之前到现在发生了任何异常,将捕获异常。解析异常得到视图,否则抛出异常。
渲染模型和视图,返回响应内容。之前得到的视图可能只是视图名,如果这样将遍历询问ViewResolver
列表查找目标视图,如果没有找到,抛出异常。
如果之前到现在发生了任何异常,将返回容器并处理异常。
2.HandlerMapping
处理器映射是将请求映射到处理器的抽象。其接口方法如下:
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
HandlerExecutionChain
封装了HandlerInterceptor
列表和处理器
对象。
HandlerInterceptor
MVC框架级别的Filter,包含了三个拦截方法:
boolean preHandle(..) — 在实际的处理器执行前调用
void postHandle(..) — 在处理器执行后调用
void afterCompletion(..) — 在请求处理结束后调用
在执行处理器之前,会执行拦截器的前置处理,可能会中断后续流程并直接返回容器。在执行处理器后,会执行拦截器的后置处理。在返回容器前,会执行拦截器的完成处理。
查找处理器逻辑
AbstractHandlerMapping是HandlerMapping的基本抽象类。其定义了getHandler()的模板方法:
从子类实现的getHandlerInternal()中得到handler。从初始化注入的拦截器列表中获取匹配的拦截器。封装得到HandlerExecutionChain。
3.HandlerAdapter
为了保证灵活性,Spring MVC没有对handler进行任何限定,而是支持任意类型的handler,并由该类型的HandlerAdapter来完成处理。
它主要定义了两个方法:
boolean supports(Object handler);//返回是否支持该处理器类型
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;//执行处理器,并返回MV
每一个HandlerMapping的实现,都对应着一个HandlerAdapter实现,只有该HandlerAdapter才知道如何调用处理器。
基于注解驱动的HandlerMapping和HandlerAdapter
对基于注解的@Controller
,@RequestMapping
提供支持的是RequestMappingHandlerMapping
和RequestMappingHandlerAdapter
。这里简单介绍一下它们的工作原理。
RequestMappingHandlerMapping
RequestMappingHandlerMapping在初始化时遍历上下文所有bean,如果其是一个控制器(声明了@Controller
或@RequestMapping
)就扫描其所有方法。如果方法是一个处理器方法(声明了@RequestMapping
)就将控制器、方法、映射信息注册到相关表中。
每次请求查找匹配的处理器,RequestMappingHandlerMapping就会查找其表,根据请求路径和其他参数返回匹配的HandlerMethod
对象。
RequestMappingHandlerAdapter
对HandlerMethod
类型的处理器提供了支持。
4.HandlerExceptionResolver
HandlerExceptionResolver处理查找和执行处理器阶段抛出的所有异常。
它的接口方法如下:
ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
一个HandlerExceptionResolver的处理方式是:
- 返回一个ModelAndView,指向确切的错误视图
- 返回一个空的ModelAndView,表示已经处理,将其转换为了错误状态码或已返回响应
- 返回null,交给链的下一个进行处理
多个处理器异常解析器会依次调用,直到其中一个处理完成。
5.ViewResolver
处理器可能返回的是一个视图对象或只是一个视图名,视图解析器负责将视图名解析为一个具体的视图对象。
其接口定义为:
View resolveViewName(String viewName, Locale locale) throws Exception;
多个视图解析器以链的方式调用,直到其中一个返回一个View
。
View
View是视图的抽象,其完成最后的内容输出功能:
void render(Map<String, ?> model, HttpServletRequest
request, HttpServletResponse response) throws Exception;
总结
本文通过跟踪请求的处理流程来大致分析了DispatcherServlet的工作原理。在理解这个过程时,切忌过于关注底层实现细节,而应该从抽象层面来理解。