现在基于请求驱动的Web框架基本都是由单一的Servlet作为整个应用程序的前置处理器(Front Controller),该Servlet接收到具体的Web处理请求之后,会参照预先可配置的映射信息,将待处理的Web请求转发给次一级的控制器来处理。
DispatcherServlet就是Spring MVC框架中的这个单一的Servlet,它就是Spring MVC框架如此简单好用的原因,我们只需要定义一个Controller,写上自己的业务逻辑之后,即可处理Web请求了。原理就是Spring MVC已经帮我们周到的设计好了整个MVC处理的流程,该流程中的每个角色各司其职,我们需要做的仅仅只是按照模板流程填充我们的Controller代码即可。DispatcherServlet就是这个流程的指挥官,负责这与各个角色之间的交互,在解析Spring MVC源码之前,有必要先介绍框架中的各个角色及其职能。
- DispatcherServlet:前置处理器,即指挥官,它本质就是Web容器里的Servlet,将各项工作细化并分离给了各个独立的角色来完成
- HandlerMapping:处理器映射器,专门管理Web请求到具体的处理类之间的映射关系
- HandlerAdaptor:处理器适配器,Spring MVC并不只是支持Controller一种Handler类型,HandlerApapter可以帮助其使用其他类型的Handler,即帮助DispatcherServlet一统调用具体Handler的方法名,这样当提供自定义的Handler时,也需提供对应的HandlerAdaptor
- Handler:处理器,负责实现对应某个具体Web请求的处理逻辑,Controller、Interceptor、Endpoint、Action(Struts)等都是处理器
- ModelAndView:逻辑视图名称和模型数据
- ViewResolver:处理逻辑视图名与具体的View实例之间的映射关系
- View:处理最终的视图渲染工作
了解了各个角色的职能后,那么这些角色间是如何交互的呢,Spring MVC处理流程如下:
其中,Handler即为我们的亲密伙伴,只需通过注解@Controller、@RequestMapping即可完成功能开发,Spring3.1之后,基于注解的Controller对应的HandlerMapping和HandlerAdapter实现类分别为:
RequestMappingHandlerMapping和RequestMappingHandlerAdapter,他们都与@RequestMapping注解相关,分别帮助指挥官找到Controller和Controller中相应的方法。
DispatcherServlet中的核心代码如下:
- 查找处理器:
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
- 查找处理器适配器:
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
- 委托处理器适配器调用Handler,返回ModelAndView:
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
处理器适配器调用Handler核心代码如下:
- 参数绑定:
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
- ModelAndView初始化:
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
- 通过反射调用Handler中业务代码:
invocableMethod.invokeAndHandle(webRequest, mavContainer);