Dispatherervlet概述
在servlet定义中,一个http请求,是通过servlet容器来访问的,会在web.xml中的配置的映射,访问到指定的servlet类。
spring中的Dispatherervlet也是一个HttpServlet。并且在springmvc中,默认所有的请求都是通过Dispatherervlet来分发具体请求的。
在servlet定义中,一个请求进入到servlet中会通过 doService(request, response) 进入到业务处理逻辑。
以下是Dispatherervlet中的doService(request, response) 方法的源码内容:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
- 第一行逻辑是打日志,暂不考虑里面细节。
- 第一部分逻辑是对include请求做快照处理(在这里的处理方式就是将原本的请求中所有的attribute保存到另一个map中暂时保存),这里简单解释一下
- include请求指的是:之前存放在HttpResponse对象中的内容将不会被清除,内容追加;
与之对应的另一个请求都比较熟悉,就是forward请求
- 之前存放在HttpResponse对象中的内容将会被清除
扩展:在这里可以看到servlet中有哪些属性
- 第二部分是把sprinbmvc中的数据传入到request中,作为attribute。传入的内容有:springmvc中的context、localeResolver、localeResolver和ThemeSource
- context是springmvc的上下文
- localeResolver是springmvc的国际化
- localeResolver和ThemeSource是springmvc提供ui的工具
- 第三部分是把flashmap的相关数据存储到request的attribute中:
- flashMapManager通过request, response检索到相对应的flashmap,并将其作为INPUT_FLASH_MAP_ATTRIBUTE放入request中
- new一个FlashMap,作为OUTPUT_FLASH_MAP_ATTRIBUTE放入request中
- 将flashMapManager放入- request中
FlashMap是什么,springmvc源码文档解释如下:
A FlashMap provides a way for one request to store attributes intended for use in another. This is most commonly needed when redirecting from one URL to another -- e.g. the Post/Redirect/Get pattern. A FlashMap is saved before the redirect (typically in the session) and is made available after the redirect and removed immediately. A FlashMap can be set up with a request path and request parameters to help identify the target request. Without this information, a FlashMap is made available to the next request, which may or may not be the intended recipient. On a redirect, the target URL is known and a FlashMap can be updated with that information. This is done automatically when the org.springframework.web.servlet.view.RedirectView is used. Note: annotated controllers will usually not use FlashMap directly. See org.springframework.web.servlet.mvc.support.RedirectAttributes for an overview of using flash attributes in annotated controllers.
简单来说,flashmap主要作用就是在redirect的时候,保存之前的attribute信息
- 然后就是重头戏--doDispatch(request, response);,待会儿再说;
- 最后是对doDispatch(request, response);的finally操作 假如本次该请求不是异步启动的,则会把之前保持的快照给copy过来
doDispatch
这个方法是springmvc中处理请求的核心方法,先将源码粘出来
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 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());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
核心逻辑是在内嵌的try块里面包住的。 核心逻辑大概是这样的流程:
- 调用getHandler(processedRequest)方法。该方法通过handlerMapping组件,获取到一个HandlerExecutionChain
- 调用getHandlerAdapter(mappedHandler.getHandler())方法。该方法通过HandlerExecutionChain获取到一个HandlerAdapter。
- 调用HandlerExecutionChain#applyPreHandle(processedRequest, response) 方法。该方法内部是这样的
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false; }
this.interceptorIndex = i;
}
}
return true;
}
applyPreHandle主要是处理HandlerInterceptor的。 在applyPreHandle 中,如果preHandle认为不需要调用handler链中后面的interceptor了(也就是preHandle返回false),它也会直接执行handler的afterCompletion。
使用过HandlerInterceptor的都知道,使用它,需要实现它的三个方法:boolean preHandle(request, response, Object handler)、void postHandle(request, response, handler, modelAndView)和void afterCompletion(request, response, handler, ex)。它们的执行流程是preHandle --> 业务方法 --> postHandle --> afterCompletion
- 调用HandlerAdapter#handle(processedRequest, response, HandlerExecutionChain#getHandler()) 方法。该方法直接调用用户开发的业务逻辑,也就是 @RequestMapping修饰的方法。 注:HandlerAdapter,有很多类型,具体使用什么类型由getHandlerAdapter来确定,具体不同类型什么时候使用这些概念这里先不讲,后面在来扩展。我们这里所说的流程中,主要使用的是RequestMappingHandlerAdapter
- 调用HandlerExecutionChain#applyPostHandle(processedRequest, response, mv) 方法,处理自定义 HandlerInterceptor中的postHandle方法
- 调用processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)。 里面有一些ModelAndView的操作,这里先不讲。 除此之外,还要处理异常的请求,清空错误的Attributes。 并且也会调用triggerAfterCompletion(processedRequest, response, mappedHandler, ex),上面讲过,该方法就是调用HandlerInterceptor中的afterCompletion方法。
- 最后为确保HandlerInterceptor中的afterCompletion方法被调用,在catch块里面再确认两遍。
- 在finally块里主要做一些收尾工作,如果是异步handler去handle请求的话,则调用AsyncHandlerInterceptor的afterConcurrentHandlingStarted的方法。如果不是这样,则清空multipart的request。
总结
以上的内容,分别讲了:
- servlet是如何处理一个请求;
- springmvc是如何通过servlet机制去接收请求的;
- DispatcherServlet的doService方法;
- DispatcherServlet的doDispatch方法;
在doDispatch方法中,主要有这些组件:
- Handler: 处理器,完成具体业务逻辑。
- HandlerMapping: DispatcherServlet 接收到请求之后,通过 HandlerMapping 将不同的请求分发到不同的 Handler。
- HandlerInterceptor: 处理器拦截器,是一个接口,如果我们需要做一些拦截处理,可以来实现这个接口。
- HandlerExecutionChain: 处理器执行链,包括两部分内容,Handler 和 HandlerInterceptor,系统会有一个默认的 HandlerInterceptor,如果需要额外拦截处理,可以添加拦截器设置。
- HandlerAdapter: 处理器适配器,DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler。
- ModelAndView: 装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。
- ViewResolver: 视图解析器,DispatcherServlet 通过它将逻辑视图解析成物理视图,最终将渲染结果响应给客户端。
关于ModelAndView和ViewResolver,本文没有讲,其它组件也只是顺嘴一提。因为这不是重点,重点是处理流程。各个组件的作用以及组成,在后续文章会讲。
再重新整理一下DispatcherServlet 的处理流程的话,doService方法把springmvc的环境,配置到reqeust中。然后调用doDispatcher方法。
doDispatcher方法的主要功能是:
- 寻找到具体的业务方法并且执行;
- 保证HandlerInterceptor的执行流程;
- 视图的解析、渲染等工作。
doDispatcher方法的整体执行流程是基于它各个组件的配合完成的。
- 通过handlerMappings 获取到 HandlerExecutionChain,HandlerExecutionChain会持有一个Handler,该Handler有可能是任何东西,是一个Object变量;
- 遍历持有的所有HandlerAdapter,检索出能够 handle HandlerExecutionChain持有的Handler 的HandlerAdapter;
- HandlerExecutionChain除了持有Handler,也持有HandlerInterceptor。这一步就需要遍历它所有的HandlerInterceptor,并且执行preHandle方法
- HandlerAdapter调用handle方法;
- 遍历HandlerExecutionChain的HandlerInterceptor,并且执行postHandle方法
- 处理最终结果