zoukankan      html  css  js  c++  java
  • 6、SpringMVC源码分析(1):分析DispatcherServlet.doDispatch方法,了解总体流程

    所有的http请求都会交给DispatcherServlet类的doDispatch方法进行处理,将DispatcherServlet.doDispatch函数的javadoc复制到下面:

    /*
         * Process the actual dispatching to the handler.
         * 
         * The handler will be obtained by applying the servlet's HandlerMappings in
         * order.The HandlerAdapter will be obtained by querying the servlet's
         * installed HandlerAdapters to find the first that supports the handler
         * class.
         * 
         * All HTTP methods are handled by this method. It's up to HandlerAdapters
         * or handlers themselves to decide which methods are acceptable.
         */
         void org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception;

    下面分析doDispatch方法的流程,采用注释源码的方式:

      1 protected void doDispatch(HttpServletRequest request,
      2             HttpServletResponse response) throws Exception {
      3         
      4         // processedRequest是经过checkMultipart方法处理过的request请求
      5         HttpServletRequest processedRequest = request;
      6         /**
      7          * Handler execution chain, consisting of handler object and any handler
      8          * interceptors. Returned by HandlerMapping's HandlerMapping.getHandler
      9          * method. 看看HandlerExecutionChain类的属性就很清楚了:
     10          * 
     11           public class HandlerExecutionChain {
     12          
     13                   private final Object handler; //这个就是和该请求对应的handler处理方法
     14          
     15                  //里面记录了所有的(any handler interceptors)和该请求相关的拦截器
     16                   private HandlerInterceptor[] interceptors;
     17           
     18                   private List<HandlerInterceptor> interceptorList; 
     19          
     20                   private int interceptorIndex = -1; 
     21                       
     22                   //... 
     23           }
     24          * 
     25          */
     26         HandlerExecutionChain mappedHandler = null;
     27         boolean multipartRequestParsed = false;
     28 
     29         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
     30 
     31         try {
     32             ModelAndView mv = null;
     33             Exception dispatchException = null;
     34 
     35             try {
     36                 processedRequest = checkMultipart(request);
     37                 multipartRequestParsed = (processedRequest != request);
     38 
     39                 // Determine handler for the current request.Return a handler
     40                 // and any interceptors for this request.
     41                 /*
     42                  * 得到的mappedHandler包含一个请求的handler处理方法以及与该请求相关的所有拦截器
     43                  * 
     44                  * DispatcherServlet.getHandler方法会在底层调用HandlerMapping.getHandler方法
     45                  * ,这个方法中会遍 历DispatcherServlet中的private List<HandlerMapping>
     46                  * handlerMappings链表,找到能够处理当前 request请求的第一个HandlerMapping实例并返回:
     47                  * 
     48                   protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
     49                       for (HandlerMapping hm : this.handlerMappings) {
     50                               HandlerExecutionChain handler = hm.getHandler(request);
     51                               if (handler != null) {
     52                                      return handler;
     53                               }
     54                       }
     55                       return null;
     56                   }
     57                  *
     58                  */
     59                 mappedHandler = getHandler(processedRequest);
     60                 // 如果没有找到和该请求相对应的mappedHandler,那么就会直接返回,并应答noHandlerFound异常
     61                 if (mappedHandler == null || mappedHandler.getHandler() == null) {
     62                     noHandlerFound(processedRequest, response);
     63                     return;
     64                 }
     65 
     66                 // Determine handler adapter for the current request.
     67                 /*
     68                  * HandlerAdapter: 它是一个接口public interface HandlerAdapter
     69                  * 看看源码上的说明:The DispatcherServlet accesses all installed
     70                  * handlers through this interface, meaning that it does not
     71                  * contain code specific to any handler type.
     72                  * 
     73                  * 从后面的源码看出,在使用@RequestMapping注解标注handler方法的时候,获取到的是HandlerAdapter的
     74                  * RequestMappingHandlerAdapter实现类的一个对象。
     75                  * 
     76                  * 可以看看DispatcherServlet.getHandlerAdapter方法的定义,这个对理解上回很有帮助,我们会发现
     77                  * ,getHandlerAdapter 方法和上面提到的getHandler方法一样都是寻找第一个可用的作为返回结果:
     78                  *
     79                  * 
     80                   protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
     81                      //this.handlerAdapters的定义是 private List<HandlerAdapter> handlerAdapters
     82                          for (HandlerAdapter ha : this.handlerAdapters) { 
     83                               if (ha.supports(handler)) {
     84                                    return ha;
     85                               }
     86                          }
     87                          throw new ServletException("No adapter for handler [" + handler +
     88                                  "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
     89                   }
     90                  * 
     91                  */
     92                 HandlerAdapter ha = getHandlerAdapter(mappedHandler
     93                         .getHandler());
     94 
     95                 // Process last-modified header, if supported by the handler.
     96                 String method = request.getMethod();
     97                 boolean isGet = "GET".equals(method);
     98                 if (isGet || "HEAD".equals(method)) {
     99                     long lastModified = ha.getLastModified(request,
    100                             mappedHandler.getHandler());
    101                     if (logger.isDebugEnabled()) {
    102                         logger.debug("Last-Modified value for ["
    103                                 + getRequestUri(request) + "] is: "
    104                                 + lastModified);
    105                     }
    106                     if (new ServletWebRequest(request, response)
    107                             .checkNotModified(lastModified) && isGet) {
    108                         return;
    109                     }
    110                 }
    111 
    112                 // Apply preHandle methods of registered interceptors.
    113                 /*
    114                  * 会调用所有注册拦截器的preHandle方法,如果preHandle方法的返回结果为true,则会继续执行下面的程序,
    115                  * 否则会直接返回。
    116                  * 
    117                  * 分析一下HandlerExecutionChain.applyPreHandle方法的源码 :
    118                   boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    119                          //从上面的HandlerExecutionChain定义处可以看见有个interceptors,还有一个interceptorList。不知道有什么区别??!
    120                          HandlerInterceptor[] interceptors = getInterceptors();
    121                          //如果已经注册有拦截器,则遍历拦截器
    122                          if (!ObjectUtils.isEmpty(interceptors)) {
    123                              for (int i = 0; i < interceptors.length; i++) {
    124                                  HandlerInterceptor interceptor = interceptors[i];
    125                                  //如果注册拦截器的preHandle方法返回一个false,则该applyPreHandle方法就会返回false,从而在doDispatcher中的代码就不会往下执行了
    126                                  if (!interceptor.preHandle(request, response, this.handler)) {
    127                                      
    128                                      //这个方法要注意,它会调用所有已经成功执行的拦截器的afterCompletion方法,而且是反序调用的过程,可以分析triggerAfterCompletion
    129                                      //的源代码,主要是利用interceptorIndex反减的方式实现的。下面是源码的英文注释:
    130                                      //Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
    131                                       //Will just invoke afterCompletion for all interceptors whose preHandle invocation
    132                                       //has successfully completed and returned true.
    133                                      triggerAfterCompletion(request, response, null);
    134                                      return false;
    135                              }
    136                                  //没成功执行一个拦截器的preHandle方法,其interceptorIndex就会增加1;原始值为-1。
    137                                   this.interceptorIndex = i;
    138                              }
    139                          }
    140                          return true;
    141                      }
    142                  *
    143                  *
    144                  *  顺带看看triggerAfterCompletion的源代码,很容易理解为什么拦截器的afterCompletion方法是反序执行的:
    145                  *    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
    146                              throws Exception {
    147                 
    148                         HandlerInterceptor[] interceptors = getInterceptors();
    149                         if (!ObjectUtils.isEmpty(interceptors)) {
    150                             for (int i = this.interceptorIndex; i >= 0; i--) {
    151                                 HandlerInterceptor interceptor = interceptors[i];
    152                                 try {
    153                                     interceptor.afterCompletion(request, response, this.handler, ex);
    154                                 }
    155                                 catch (Throwable ex2) {
    156                                     logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
    157                                 }
    158                             }
    159                         }
    160                     }
    161                  *
    162                  *
    163                  */
    164                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    165                     return;
    166                 }
    167 
    168                 // Actually invoke the handler.
    169                 /*
    170                  * 在这个函数里面会真正的执行request请求相对于的handler方法,可以想象:在真正调用方法之前还会有很多的
    171                  * 先前处理。在这里仅仅是分析出大概的代码执行流程,其细节的部分在后面的单独模块源码分析的时候做详细的讲解。
    172                  * 上面讲解到HandlerAdapter是一个接口:public interface HandlerAdapter,那么必然会有很多
    173                  * 中实现类,在采用注解@RequstMapping的方式标注handler的情况下,ha.handle方法会在底层调用具体的
    174                  * HandlerAdapter类实现方法RequestMappingHandlerAdapter.handleInternal
    175                  * 
    176                  * 分析一下RequestMappingHandlerAdapter.handleInternal的源代码:
    177                       protected ModelAndView handleInternal(HttpServletRequest request,
    178                         HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    179                         //好像是看control的类定义处是否使用了@SessionAttributes注解,checkAndPrepare方法有什么作用???
    180                         if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
    181                             // Always prevent caching in case of session attribute management.
    182                             checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
    183                         }
    184                         else {
    185                             // Uses configured default cacheSeconds setting.
    186                             checkAndPrepare(request, response, true);
    187                         }
    188                         
    189                         // Execute invokeHandlerMethod in synchronized block if required.
    190                         // 这里是个值得注意的地方,synchronizeOnSession的值默认为false,如果通过某个方法使得其为true,那么request对应的handler
    191                         // 将会被放在同步快中进行处理。在什么时机下,使用什么方法才能将其设置为true呢???
    192                         if (this.synchronizeOnSession) {
    193                             HttpSession session = request.getSession(false);
    194                             if (session != null) {
    195                                 Object mutex = WebUtils.getSessionMutex(session);
    196                                 // 将handler放在同步块中处理
    197                                 synchronized (mutex) {
    198                                     return invokeHandleMethod(request, response, handlerMethod);
    199                                 }
    200                             }
    201                         }
    202                         //在invokeHandleMethod中会①将所有标注有@ModelAttrib的方法都执行一遍,②调用invokeAndHandle(webRequest, mavContainer)
    203                         //方法,在这里面调用handler方法,③最后调用getModelAndView(mavContainer, modelFactory, webRequest)方法的到ModelAndView。
    204                         //invokeHandleMethod这个方法还有很多东西要分析,留在后面。
    205                         //从上面的③我们可以看出,无论handler采用哪种模型化处理方式,最后都是将结果转化为ModelAndView
    206                         return invokeHandleMethod(request, response, handlerMethod);
    207                     }
    208                  */
    209                 mv = ha.handle(processedRequest, response,
    210                         mappedHandler.getHandler());
    211 
    212                 if (asyncManager.isConcurrentHandlingStarted()) {
    213                     return;
    214                 }
    215 
    216                 applyDefaultViewName(request, mv);
    217                 /*
    218                  * 调用request相关的拦截器的postHandle方法,注意,这个也是反序调用的。看看源代码:
    219                  *
    220                   void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
    221                         HandlerInterceptor[] interceptors = getInterceptors();
    222                         if (!ObjectUtils.isEmpty(interceptors)) {
    223                             //注意,这里也是反序执行,而且是所有成功执行了的postHandle拦截器
    224                             for (int i = interceptors.length - 1; i >= 0; i--) {
    225                                 HandlerInterceptor interceptor = interceptors[i];
    226                                 //这里传入的参数中有mv,也就是说,我们是有办法在拦截器的postHandle方法中修改已经返回的mv
    227                                 interceptor.postHandle(request, response, this.handler, mv);
    228                             }
    229                         }
    230                     }
    231                  */
    232                 mappedHandler.applyPostHandle(processedRequest, response, mv);
    233             } catch (Exception ex) {
    234                 dispatchException = ex;
    235             }
    236             processDispatchResult(processedRequest, response, mappedHandler,
    237                     mv, dispatchException);
    238         } catch (Exception ex) {
    239             triggerAfterCompletion(processedRequest, response, mappedHandler,
    240                     ex);
    241         } catch (Error err) {
    242             triggerAfterCompletionWithError(processedRequest, response,
    243                     mappedHandler, err);
    244         } finally {
    245             if (asyncManager.isConcurrentHandlingStarted()) {
    246                 // Instead of postHandle and afterCompletion
    247                 if (mappedHandler != null) {
    248                     mappedHandler.applyAfterConcurrentHandlingStarted(
    249                             processedRequest, response);
    250                 }
    251             } else {
    252                 // Clean up any resources used by a multipart request.
    253                 if (multipartRequestParsed) {
    254                     cleanupMultipart(processedRequest);
    255                 }
    256             }
    257         }
    258     }

    看完源代码就可以总结出doDispath方法中处理http请求的流程了:

  • 相关阅读:
    Codeforces 938G(cdq分治+可撤销并查集+线性基)
    codeforces 938F(dp+高维前缀和)
    寒武纪camp Day6
    寒武纪camp Day5
    寒武纪camp Day4
    bzoj4161 (k^2logn求线性递推式)
    loj10003加工生产调度
    loj10002喷水装置
    loj10001种树
    bzoj1023
  • 原文地址:https://www.cnblogs.com/lj95801/p/4961456.html
Copyright © 2011-2022 走看看