springMVC源碼分析--DispatcherServlet請求獲取及處理

在之前的博客 springMVC源碼分析--容器初始化(二)DispatcherServlet中我們介紹過DispatcherServlet,是在容器初始化過程中出現的,我們之前也說過DispatcherServlet其實就是一個HttpServlet,其實他是HttpServlet的子類,所以它和普通的HttpServlet有同樣的配置:

[html] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:14px;"><span style="white-space:pre">    </span><servlet>  
  2.         <servlet-name>springmvc</servlet-name>  
  3.         <servlet-class>  
  4.             org.springframework.web.servlet.DispatcherServlet  
  5.         </servlet-class>  
  6.         <init-param>  
  7.             <param-name>contextConfigLocation</param-name>  
  8.             <param-value>classpath:springmvc-config.xml</param-value>  
  9.         </init-param>  
  10.         <load-on-startup>1</load-on-startup>      
  11.     </servlet>  
  12.   
  13.     <servlet-mapping>  
  14.         <servlet-name>springmvc</servlet-name>  
  15.         <url-pattern>*.action</url-pattern>  
  16.     </servlet-mapping></span>  
僅僅把DispatcherServlet當做一個Servlet的話,上面配置的含義就是這個Servlet會被所有的*.action的請求所調用。

既然DispatcherServlet是一個HttpServlet那麼它應該會實現HttpServlet提供的如下方法:


當然這些所有的方法的實現是DispatcherServlet的父類FrameworkServlet中實現的。


當然這些實現方法中的默認實現其實是如下的

FrameworkServlet類中

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2.     protected final void doPost(HttpServletRequest request, HttpServletResponse response)  
  3.             throws ServletException, IOException {  
  4.   
  5.         processRequest(request, response);  
  6.     }  
[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2.     protected final void doGet(HttpServletRequest request, HttpServletResponse response)  
  3.             throws ServletException, IOException {  
  4.   
  5.         processRequest(request, response);  
  6.     }  
processRequest的實現是在FrameworkServlet中,此方法中最主要的操作就是調用doService方法
[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. protected final void processRequest(HttpServletRequest request, HttpServletResponse response)  
  2.             throws ServletException, IOException {  
  3.   
  4.         long startTime = System.currentTimeMillis();  
  5.         Throwable failureCause = null;  
  6.   
  7.         LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();  
  8.         LocaleContext localeContext = buildLocaleContext(request);  
  9.   
  10.         RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();  
  11.         ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);  
  12.   
  13.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  14.         asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());  
  15.   
  16.         initContextHolders(request, localeContext, requestAttributes);  
  17.   
  18.         try {  
  19.             doService(request, response);  
  20.         }  
  21.         catch (ServletException ex) {  
  22.             failureCause = ex;  
  23.             throw ex;  
  24.         }  
  25.         catch (IOException ex) {  
  26.             failureCause = ex;  
  27.             throw ex;  
  28.         }  
  29.         catch (Throwable ex) {  
  30.             failureCause = ex;  
  31.             throw new NestedServletException("Request processing failed", ex);  
  32.         }  
  33.   
  34.         finally {  
  35.             resetContextHolders(request, previousLocaleContext, previousAttributes);  
  36.             if (requestAttributes != null) {  
  37.                 requestAttributes.requestCompleted();  
  38.             }  
  39.   
  40.             if (logger.isDebugEnabled()) {  
  41.                 if (failureCause != null) {  
  42.                     this.logger.debug("Could not complete request", failureCause);  
  43.                 }  
  44.                 else {  
  45.                     if (asyncManager.isConcurrentHandlingStarted()) {  
  46.                         logger.debug("Leaving response open for concurrent processing");  
  47.                     }  
  48.                     else {  
  49.                         this.logger.debug("Successfully completed request");  
  50.                     }  
  51.                 }  
  52.             }  
  53.   
  54.             publishRequestHandledEvent(request, response, startTime, failureCause);  
  55.         }  
  56.     }  

doService方法的最終實現是在DispatcherServlet中,這樣所有的Http請求(GET、POST、PUT和DELETE等)的最終操作就DispatcherServlet中實現了。

DispatcherServlet中doService的實現如下,對Request設置了一些全局屬性,最終接下來的操作是在doDispatcher函數中實現了。

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. //獲取請求,設置一些request的參數,然後分發給doDispatch  
  2.     @Override  
  3.     protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  4.         if (logger.isDebugEnabled()) {  
  5.             String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";  
  6.             logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +  
  7.                     " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");  
  8.         }  
  9.   
  10.         // Keep a snapshot of the request attributes in case of an include,  
  11.         // to be able to restore the original attributes after the include.  
  12.         Map<String, Object> attributesSnapshot = null;  
  13.         if (WebUtils.isIncludeRequest(request)) {  
  14.             attributesSnapshot = new HashMap<String, Object>();  
  15.             Enumeration<?> attrNames = request.getAttributeNames();  
  16.             while (attrNames.hasMoreElements()) {  
  17.                 String attrName = (String) attrNames.nextElement();  
  18.                 if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {  
  19.                     attributesSnapshot.put(attrName, request.getAttribute(attrName));  
  20.                 }  
  21.             }  
  22.         }  
  23.   
  24.         // Make framework objects available to handlers and view objects.  
  25.         /* 設置web應用上下文**/  
  26.         request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());  
  27.         /* 國際化本地**/  
  28.         request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);  
  29.         /* 樣式**/  
  30.         request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);  
  31.         //設置樣式資源  
  32.         request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());  
  33.         //請求刷新時保存屬性  
  34.         FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);  
  35.         if (inputFlashMap != null) {  
  36.             request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));  
  37.         }  
  38.         //Flash attributes 在對請求的重定向生效之前被臨時存儲(通常是在session)中,並且在重定向之後被立即移除  
  39.         request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());  
  40.         //FlashMap 被用來管理 flash attributes 而 FlashMapManager 則被用來存儲,獲取和管理 FlashMap 實體.  
  41.         request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);  
  42.   
  43.         try {  
  44.             doDispatch(request, response);  
  45.         }  
  46.         finally {  
  47.             if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {  
  48.                 // Restore the original attribute snapshot, in case of an include.  
  49.                 if (attributesSnapshot != null) {  
  50.                     restoreAttributesAfterInclude(request, attributesSnapshot);  
  51.                 }  
  52.             }  
  53.         }  
  54.     }  
doDispatch函數中完成了對一個請求的所有操作,包含的內容還是比較多的,我們就不做詳細分解,接下來我們會一步一步的分析一個請求調用Controller的完整過程。

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. /** 
  2.      *將Handler進行分發,handler會被handlerMapping有序的獲得 
  3.      *通過查詢servlet安裝的HandlerAdapters來獲得HandlerAdapters來查找第一個支持handler的類 
  4.      *所有的HTTP的方法都會被這個方法掌控。取決於HandlerAdapters 或者handlers 他們自己去決定哪些方法是可用 
  5.      *@param request current HTTP request 
  6.      *@param response current HTTP response 
  7.      */  
  8.     protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  9.         /* 當前HTTP請求**/  
  10.         HttpServletRequest processedRequest = request;  
  11.         HandlerExecutionChain mappedHandler = null;  
  12.         boolean multipartRequestParsed = false;  
  13.   
  14.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  15.   
  16.         try {  
  17.             ModelAndView mv = null;  
  18.             Exception dispatchException = null;  
  19.   
  20.             try {  
  21.                 //判斷是否有文件上傳  
  22.                 processedRequest = checkMultipart(request);  
  23.                 multipartRequestParsed = (processedRequest != request);  
  24.   
  25.                 // 獲得HandlerExecutionChain,其包含HandlerIntercrptor和HandlerMethod  
  26.                 mappedHandler = getHandler(processedRequest);  
  27.                 if (mappedHandler == null || mappedHandler.getHandler() == null) {  
  28.                     noHandlerFound(processedRequest, response);  
  29.                     return;  
  30.                 }  
  31.   
  32.                   
  33.                 //獲得HandlerAdapter  
  34.                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  35.   
  36.                 //獲得HTTP請求方法  
  37.                 String method = request.getMethod();  
  38.                 boolean isGet = "GET".equals(method);  
  39.                 if (isGet || "HEAD".equals(method)) {  
  40.                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
  41.                     if (logger.isDebugEnabled()) {  
  42.                         logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);  
  43.                     }  
  44.                     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
  45.                         return;  
  46.                     }  
  47.                 }  
  48.                 //如果有攔截器的話,會執行攔截器的preHandler方法  
  49.                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
  50.                     return;  
  51.                 }  
  52.   
  53.                 //返回ModelAndView  
  54.                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
  55.   
  56.                 if (asyncManager.isConcurrentHandlingStarted()) {  
  57.                     return;  
  58.                 }  
  59.                 //當view爲空時,,根據request設置默認view  
  60.                 applyDefaultViewName(processedRequest, mv);  
  61.                 //執行攔截器的postHandle  
  62.                 mappedHandler.applyPostHandle(processedRequest, response, mv);  
  63.             }  
  64.             catch (Exception ex) {  
  65.                 dispatchException = ex;  
  66.             }  
  67.             processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
  68.         }  
  69.         catch (Exception ex) {  
  70.             triggerAfterCompletion(processedRequest, response, mappedHandler, ex);  
  71.         }  
  72.         catch (Error err) {  
  73.             triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);  
  74.         }  
  75.         finally {  
  76.             //判斷是否是異步請求  
  77.             if (asyncManager.isConcurrentHandlingStarted()) {  
  78.                 // Instead of postHandle and afterCompletion  
  79.                 if (mappedHandler != null) {  
  80.                     mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  
  81.                 }  
  82.             }  
  83.             else {  
  84.                 // Clean up any resources used by a multipart request.  
  85.                 //刪除上傳資源  
  86.                 if (multipartRequestParsed) {  
  87.                     cleanupMultipart(processedRequest);  
  88.                 }  
  89.             }  
  90.         }  
  91.     }  
調用完doDispatch之後就完成了一個請求的訪問,其會將渲染後的頁面或者數據返回給請求發起者。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章