Dispatherervlet执行流程概述

159 阅读7分钟

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);  
  }  
      }  
   }  
}
  1. 第一行逻辑是打日志,暂不考虑里面细节。
  2. 第一部分逻辑是对include请求做快照处理(在这里的处理方式就是将原本的请求中所有的attribute保存到另一个map中暂时保存),这里简单解释一下
  • include请求指的是:之前存放在HttpResponse对象中的内容将不会被清除,内容追加;

与之对应的另一个请求都比较熟悉,就是forward请求

  • 之前存放在HttpResponse对象中的内容将会被清除

扩展:在这里可以看到servlet中有哪些属性

  1. 第二部分是把sprinbmvc中的数据传入到request中,作为attribute。传入的内容有:springmvc中的contextlocaleResolverlocaleResolverThemeSource
  • contextspringmvc的上下文
  • localeResolverspringmvc的国际化
  • localeResolverThemeSourcespringmvc提供ui的工具
  1. 第三部分是把flashmap的相关数据存储到requestattribute中:
  • 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信息

  1. 然后就是重头戏--doDispatch(request, response);,待会儿再说;
  2. 最后是对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块里面包住的。 核心逻辑大概是这样的流程:

  1. 调用getHandler(processedRequest)方法。该方法通过handlerMapping组件,获取到一个HandlerExecutionChain
  2. 调用getHandlerAdapter(mappedHandler.getHandler())方法。该方法通过HandlerExecutionChain获取到一个HandlerAdapter
  3. 调用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),它也会直接执行handlerafterCompletion

使用过HandlerInterceptor的都知道,使用它,需要实现它的三个方法:boolean preHandle(request, response, Object handler)void postHandle(request, response, handler, modelAndView)void afterCompletion(request, response, handler, ex)。它们的执行流程是preHandle --> 业务方法 --> postHandle --> afterCompletion

  1. 调用HandlerAdapter#handle(processedRequest, response, HandlerExecutionChain#getHandler()) 方法。该方法直接调用用户开发的业务逻辑,也就是 @RequestMapping修饰的方法。 注:HandlerAdapter,有很多类型,具体使用什么类型由getHandlerAdapter来确定,具体不同类型什么时候使用这些概念这里先不讲,后面在来扩展。我们这里所说的流程中,主要使用的是RequestMappingHandlerAdapter
  2. 调用HandlerExecutionChain#applyPostHandle(processedRequest, response, mv) 方法,处理自定义 HandlerInterceptor中的postHandle方法
  3. 调用processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)。 里面有一些ModelAndView的操作,这里先不讲。 除此之外,还要处理异常的请求,清空错误的Attributes。 并且也会调用triggerAfterCompletion(processedRequest, response, mappedHandler, ex),上面讲过,该方法就是调用HandlerInterceptor中的afterCompletion方法。
  4. 最后为确保HandlerInterceptor中的afterCompletion方法被调用,在catch块里面再确认两遍。
  5. finally块里主要做一些收尾工作,如果是异步handlerhandle请求的话,则调用AsyncHandlerInterceptorafterConcurrentHandlingStarted的方法。如果不是这样,则清空multipartrequest

总结

以上的内容,分别讲了:

  1. servlet是如何处理一个请求;
  2. springmvc是如何通过servlet机制去接收请求的;
  3. DispatcherServletdoService方法;
  4. DispatcherServletdoDispatch方法;

doDispatch方法中,主要有这些组件:

  • Handler: 处理器,完成具体业务逻辑。
  • HandlerMapping: DispatcherServlet 接收到请求之后,通过 HandlerMapping 将不同的请求分发到不同的 Handler。
  • HandlerInterceptor: 处理器拦截器,是一个接口,如果我们需要做一些拦截处理,可以来实现这个接口。
  • HandlerExecutionChain: 处理器执行链,包括两部分内容,Handler 和 HandlerInterceptor,系统会有一个默认的 HandlerInterceptor,如果需要额外拦截处理,可以添加拦截器设置。
  • HandlerAdapter: 处理器适配器,DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler。
  • ModelAndView: 装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。
  • ViewResolver: 视图解析器,DispatcherServlet 通过它将逻辑视图解析成物理视图,最终将渲染结果响应给客户端。

关于ModelAndViewViewResolver,本文没有讲,其它组件也只是顺嘴一提。因为这不是重点,重点是处理流程。各个组件的作用以及组成,在后续文章会讲。

再重新整理一下DispatcherServlet 的处理流程的话,doService方法把springmvc的环境,配置到reqeust中。然后调用doDispatcher方法。

doDispatcher方法的主要功能是:

  1. 寻找到具体的业务方法并且执行;
  2. 保证HandlerInterceptor的执行流程;
  3. 视图的解析、渲染等工作。

doDispatcher方法的整体执行流程是基于它各个组件的配合完成的。

  • 通过handlerMappings 获取到 HandlerExecutionChainHandlerExecutionChain会持有一个Handler,该Handler有可能是任何东西,是一个Object变量;
  • 遍历持有的所有HandlerAdapter,检索出能够 handle HandlerExecutionChain持有的HandlerHandlerAdapter
  • HandlerExecutionChain除了持有Handler,也持有HandlerInterceptor。这一步就需要遍历它所有的HandlerInterceptor,并且执行preHandle方法
  • HandlerAdapter调用handle方法;
  • 遍历HandlerExecutionChainHandlerInterceptor,并且执行postHandle方法
  • 处理最终结果