SpringMVC源码分析(1):分析DispatcherServlet.doDispatch方法,了解总体流程

本文主要是介绍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请求的流程了:

这篇关于SpringMVC源码分析(1):分析DispatcherServlet.doDispatch方法,了解总体流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/973872

相关文章

Java集合中的List超详细讲解

《Java集合中的List超详细讲解》本文详细介绍了Java集合框架中的List接口,包括其在集合中的位置、继承体系、常用操作和代码示例,以及不同实现类(如ArrayList、LinkedList和V... 目录一,List的继承体系二,List的常用操作及代码示例1,创建List实例2,增加元素3,访问元

Java中将异步调用转为同步的五种实现方法

《Java中将异步调用转为同步的五种实现方法》本文介绍了将异步调用转为同步阻塞模式的五种方法:wait/notify、ReentrantLock+Condition、Future、CountDownL... 目录异步与同步的核心区别方法一:使用wait/notify + synchronized代码示例关键

Java 8 Stream filter流式过滤器详解

《Java8Streamfilter流式过滤器详解》本文介绍了Java8的StreamAPI中的filter方法,展示了如何使用lambda表达式根据条件过滤流式数据,通过实际代码示例,展示了f... 目录引言 一.Java 8 Stream 的过滤器(filter)二.Java 8 的 filter、fi

Java中实现订单超时自动取消功能(最新推荐)

《Java中实现订单超时自动取消功能(最新推荐)》本文介绍了Java中实现订单超时自动取消功能的几种方法,包括定时任务、JDK延迟队列、Redis过期监听、Redisson分布式延迟队列、Rocket... 目录1、定时任务2、JDK延迟队列 DelayQueue(1)定义实现Delayed接口的实体类 (

springboot的调度服务与异步服务使用详解

《springboot的调度服务与异步服务使用详解》本文主要介绍了Java的ScheduledExecutorService接口和SpringBoot中如何使用调度线程池,包括核心参数、创建方式、自定... 目录1.调度服务1.1.JDK之ScheduledExecutorService1.2.spring

将java程序打包成可执行文件的实现方式

《将java程序打包成可执行文件的实现方式》本文介绍了将Java程序打包成可执行文件的三种方法:手动打包(将编译后的代码及JRE运行环境一起打包),使用第三方打包工具(如Launch4j)和JDK自带... 目录1.问题提出2.如何将Java程序打包成可执行文件2.1将编译后的代码及jre运行环境一起打包2

Java使用Tesseract-OCR实战教程

《Java使用Tesseract-OCR实战教程》本文介绍了如何在Java中使用Tesseract-OCR进行文本提取,包括Tesseract-OCR的安装、中文训练库的配置、依赖库的引入以及具体的代... 目录Java使用Tesseract-OCRTesseract-OCR安装配置中文训练库引入依赖代码实

Java中对象的创建和销毁过程详析

《Java中对象的创建和销毁过程详析》:本文主要介绍Java中对象的创建和销毁过程,对象的创建过程包括类加载检查、内存分配、初始化零值内存、设置对象头和执行init方法,对象的销毁过程由垃圾回收机... 目录前言对象的创建过程1. 类加载检查2China编程. 分配内存3. 初始化零值4. 设置对象头5. 执行

SpringBoot整合easy-es的详细过程

《SpringBoot整合easy-es的详细过程》本文介绍了EasyES,一个基于Elasticsearch的ORM框架,旨在简化开发流程并提高效率,EasyES支持SpringBoot框架,并提供... 目录一、easy-es简介二、实现基于Spring Boot框架的应用程序代码1.添加相关依赖2.添

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1