天天看點

Spring MVC的使用者請求到Servlet到DispatcherServlet的流轉過程(參考B站雷豐陽的視訊筆記切圖、為了複習用。)

想看視訊的請跳轉

https://www.bilibili.com/video/BV1d4411g7tv

springmvc的整體從開始到頁面的流程說明

Spring MVC的使用者請求到Servlet到DispatcherServlet的流轉過程(參考B站雷豐陽的視訊筆記切圖、為了複習用。)
Spring MVC的使用者請求到Servlet到DispatcherServlet的流轉過程(參考B站雷豐陽的視訊筆記切圖、為了複習用。)
Spring MVC的使用者請求到Servlet到DispatcherServlet的流轉過程(參考B站雷豐陽的視訊筆記切圖、為了複習用。)

下面是自己根據調試步驟檢視的源碼,spring版本不同已經和視訊的講解有出入了

Spring MVC的使用者請求到Servlet到DispatcherServlet的流轉過程(參考B站雷豐陽的視訊筆記切圖、為了複習用。)

java提供了核心Servlet接口,該接口提供了這幾個核心的方法,初始化、服務、銷毀。

init方法和destory需要開發者自行實作,被 容器自動調用。

public abstract void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException;
           

service方法被Servlet的子類 GenericServlet實作

Spring MVC的使用者請求到Servlet到DispatcherServlet的流轉過程(參考B站雷豐陽的視訊筆記切圖、為了複習用。)
Spring MVC的使用者請求到Servlet到DispatcherServlet的流轉過程(參考B站雷豐陽的視訊筆記切圖、為了複習用。)

這裡将 ServletRequest做了強轉然後調用了HttpServlet的service方法,然後在方法裡根據請求的方式調用了FrameworkServlet的doGet或者doPost方法,此外還處理了doPut和doDelete(相當于doPost)、doHead(最終調用的doGet方法)等特殊方法。

Spring MVC的使用者請求到Servlet到DispatcherServlet的流轉過程(參考B站雷豐陽的視訊筆記切圖、為了複習用。)
Spring MVC的使用者請求到Servlet到DispatcherServlet的流轉過程(參考B站雷豐陽的視訊筆記切圖、為了複習用。)
最終來看下FrameworkServlet的processRequest方法
           
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   processRequest(request, response);
}
           
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   long startTime = System.currentTimeMillis();
   Throwable failureCause = null;

   LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
   LocaleContext localeContext = buildLocaleContext(request);

   RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
   ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
   asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

   initContextHolders(request, localeContext, requestAttributes);

   try {
      doService(request, response);//此處為真正執行請求處理
   }
   catch (ServletException | IOException ex) {
      failureCause = ex;
      throw ex;
   }
   catch (Throwable ex) {
      failureCause = ex;
      throw new NestedServletException("Request processing failed", ex);
   }

   finally {
      resetContextHolders(request, previousLocaleContext, previousAttributes);
      if (requestAttributes != null) {
         requestAttributes.requestCompleted();
      }
      logResult(request, response, failureCause, asyncManager);
      publishRequestHandledEvent(request, response, startTime, failureCause);
   }
}
           

此方法前面做了一些初始化工作。像

initContextHolders(request, localeContext, requestAttributes);對于inheritableRequestAttributesHolder的指派、
           
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
           
request的初始化
           

攔截器的初始化

最終是調用了唯一子類DispatcherServlet的doService

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);
         }
      }
   }
}
           

給request設定了一堆屬性最終調用了doDispatch()方法

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);//根據目前請求位址,找到與之适配的處理類(contorller)
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);//沒找到适配的處理器就404
            return;
         }

         // Determine handler adapter for the current request.
   HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//得到執行處理類的适配的方法(@RequestMapping)
 //3.1之前版本ha是一個AnnotationMethodHandlerAdapter,之後是RequestMappingHandlerMapping和       RequestMappingHandlerAdapter。之後是SimpleControllerHandlerAdapter的handle 之後調用了AbstractController的handle方法
           
,最終判斷controller是否有方法

         // 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.
         //通過擴充卡,适配符合的擴充卡方法去執行并将傳回值設定到ModelAndView的viewName。
         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);
         }
      }
   }
}
           

繼續閱讀