Spring MVC 關(guān)鍵流程源碼分析

Spring MVC 源碼分析

1. 前端控制器DispatcherServlet繼承結(jié)構(gòu)

前端控制器繼承結(jié)構(gòu)

前端控制器DispatcherServlet繼承自FrameworkServlet。FrameworkServlet繼承自HttpServletBean,并實(shí)現(xiàn)了ApplicationContextAware接口。HttpServletBean又繼承自HttpServlet。當(dāng)用戶發(fā)起一個(gè)請(qǐng)求,首先會(huì)被HttpServlet中的doGet/doPost處理,通過(guò)分析DispatcherServlet的繼承結(jié)構(gòu),可以發(fā)現(xiàn)用戶發(fā)起的請(qǐng)求實(shí)際被FrameworkServlet(重寫(xiě)了HttpServlet中的doGet、doPost方法)中的doGet/doPost處理,F(xiàn)rameworkServlet的doGet/doPost方法收到用戶發(fā)起的請(qǐng)求后,會(huì)調(diào)用processRequest方法處理,processRequest函數(shù)內(nèi)部會(huì)調(diào)用一個(gè)抽象方法doService,該方法在DispatcherServlet中被實(shí)現(xiàn)。DispatcherServlet中的doService方法最終會(huì)調(diào)用doDispatch核心方法處理請(qǐng)求。

2. SpringMVC處理請(qǐng)求的重要時(shí)機(jī)

2.1. Handler方法的執(zhí)行時(shí)機(jī)

通過(guò)在Controller中加入斷點(diǎn),開(kāi)啟Debug調(diào)試,分析SpringMVC處理請(qǐng)求的掉用棧,可以明確看到用戶的請(qǐng)求進(jìn)入DispatcherServlet中的doDispatch函數(shù),由此可見(jiàn)用戶都請(qǐng)求都是被doDispatch函數(shù)處理。

Controller斷點(diǎn)

2.2. 頁(yè)面渲染時(shí)機(jī)

通過(guò)在 Jsp 中加入斷點(diǎn),啟動(dòng)Debug調(diào)試,當(dāng)Controller處理完用戶請(qǐng)求后,向頁(yè)面響應(yīng),分析SpringMVC響應(yīng)請(qǐng)求的調(diào)用棧。分析調(diào)用??梢钥闯鯠ispatcherServlet中的doDispatch函數(shù)處理完用戶請(qǐng)求,緊接著調(diào)用processDispatchResult函數(shù),將用戶請(qǐng)求響應(yīng)到頁(yè)面。

jsp頁(yè)面斷點(diǎn)

2.3. doDispatch源碼分析

通過(guò)分析Handler方法的執(zhí)行時(shí)機(jī)和頁(yè)面渲染時(shí)機(jī),可以看到用戶發(fā)起一個(gè)請(qǐng)求,最終調(diào)用到了DispatcherServlet中的doDispatch方法,在doDispatch方法中主要會(huì)執(zhí)行以下邏輯完成對(duì)用戶的請(qǐng)求處理以及處理結(jié)果的響應(yīng):

  1. 首先會(huì)執(zhí)行checkMultipart函數(shù),檢查是否為文件上傳請(qǐng)求,如果當(dāng)前請(qǐng)求是上傳的請(qǐng)求,會(huì)將processedRequest變量置成true,交給后續(xù)業(yè)務(wù)處理;
  2. 調(diào)用getHandler(processedRequest)函數(shù),獲取處理當(dāng)前請(qǐng)求的Controller,也稱(chēng)為Handler。getHandler(processedRequest)方法不是直接返回Controller,而是返回HandlerExecutionChain請(qǐng)求處理鏈對(duì)象,這個(gè)對(duì)象封裝了Handler和Inteceptor。如果Handler為空就會(huì)通過(guò)noHandlerFound函數(shù)向頁(yè)面返回404;
  3. 接著通過(guò)getHandlerAdapter(mappedHandler.getHandler())函數(shù)獲取HandlerAdapter處理器適配器;
  4. 最終調(diào)用HandlerAdapter的handle方法(ha.handle(processedRequest, response, mappedHandler.getHandler()))處理請(qǐng)求,并將處理請(qǐng)求的結(jié)果封裝到ModleAndView對(duì)象中;
  5. 處理ModleAndView對(duì)象,通過(guò)processDispatchResult函數(shù)將處理請(qǐng)求的結(jié)果響應(yīng)到頁(yè)面。
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
    //執(zhí)行器鏈,包含攔截器
        HandlerExecutionChain mappedHandler = null;
    //是否是文件上傳組件
        boolean multipartRequestParsed = false;
        //異步管理器
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                // 1 檢查是否是文件上傳的請(qǐng)求
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // Determine handler for the current request.
                /*
                    2 取得處理當(dāng)前請(qǐng)求的Controller,這里也稱(chēng)為Handler,即處理器
                      這里并不是直接返回 Controller,而是返回 HandlerExecutionChain 請(qǐng)求處理鏈對(duì)象
                      該對(duì)象封裝了Handler和Inteceptor
                 */
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    // 如果 handler 為空,則返回404
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                // 3 獲取處理請(qǐng)求的處理器適配器 HandlerAdapter
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                // 處理 last-modified 請(qǐng)求頭
                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.
                // 4 實(shí)際處理器處理請(qǐng)求,返回結(jié)果視圖對(duì)象
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                // 結(jié)果視圖對(duì)象的處理
                applyDefaultViewName(processedRequest, mv);
        //攔截器的第二個(gè)攔截時(shí)機(jī),在業(yè)務(wù)處理器(即Controller類(lèi))處理完請(qǐng)求后,會(huì)執(zhí)行postHandle()方法。
                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);
            }
      //將處理好的結(jié)果響應(yīng)到頁(yè)面
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            //最終會(huì)調(diào)用HandlerInterceptor的afterCompletion 方法,在DispatcherServlet處理完請(qǐng)求之后,才會(huì)執(zhí)行afterCompletion()方法
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            //最終會(huì)調(diào)用HandlerInterceptor的afterCompletion 方法,在DispatcherServlet處理完請(qǐng)求之后,才會(huì)執(zhí)行afterCompletion()方法
            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);
                }
            }
        }
    }

doDispatch方法核心步驟:

  • 調(diào)用getHandler()獲取到能夠處理當(dāng)前請(qǐng)求的執(zhí)行鏈HandlerExecutionChain;
  • 調(diào)用getHandlerAdapter()方法,獲取能夠執(zhí)行g(shù)etHandler()獲取到的Handler的適配器;
  • 適配器調(diào)用Handler執(zhí)行ha.handle(),總能返回一個(gè)ModleAndView對(duì)象;
  • 調(diào)用processDispatchResult()方法完成頁(yè)面渲染跳轉(zhuǎn)。

2.4. 核心步驟getHandler()方法剖析

通過(guò)在doDispatch函數(shù)調(diào)用getHandler()方法上加入斷點(diǎn),分析getHandler()方法是如何獲取HandlerExecutionChain執(zhí)行器鏈

doDispatch方法

通過(guò)斷點(diǎn)向下執(zhí)行,進(jìn)入到getHandler()方法可以到獲取到了兩個(gè)handlerMappings,分別是:

  1. BeanNameUrlHandlerMapping是SpringMVC早期的使用方式,直接在類(lèi)中實(shí)現(xiàn)Controller接口,這種方式現(xiàn)在很少用了;
  2. RequestMappingHandlerMapping是SpringMVC目前最流行的使用方式,通過(guò)在類(lèi)上添加@Controller、@RequestMapping注解實(shí)現(xiàn)
getHandler方法

getHandler方法執(zhí)行步驟:

  1. 判斷handlerMappings是否為null,不為null繼續(xù)向下執(zhí)行;
  2. 通過(guò)for循環(huán)獲取到具體的HandlerMapping對(duì)象;
  3. 在for循環(huán)中通過(guò)HandlerMapping的getHandler()方法,獲取到能處理當(dāng)前請(qǐng)求的HandlerExecutionChain對(duì)象;
  4. 判斷HandlerExecutionChain對(duì)象是否為null,不為null表示獲取到處理當(dāng)前請(qǐng)求的HandlerExecutionChain,并向上返回。

2.5. 核心步驟getHandlerAdapter方法剖析

2.5.1. getHandlerAdapter執(zhí)行流程分析

通過(guò)在doDispatch函數(shù)調(diào)用getHandlerAdapter方法獲取HandlerAdapter處加入斷點(diǎn),分析getHandlerAdapter函數(shù)的執(zhí)行流程

doDispatch

斷點(diǎn)進(jìn)入getHandlerAdapter函數(shù),可以看到SpringMVC內(nèi)部有三種HandlerAdapter,分別是:

  1. HttpRequestHandlerAdapter處理器適配器能夠處理的請(qǐng)求需要實(shí)現(xiàn)HttpRequestHandler接口;
  2. SimpleControllerHandlerAdpter處理器適配器能夠處理的請(qǐng)求需要實(shí)現(xiàn)Controller接口;
  3. RequestMappingHandlerAdpter處理器適配器能夠處理在Controller中的方法上加入了@Controller、@RequestMapping注解的請(qǐng)求,也就是我們現(xiàn)在訪問(wèn)的請(qǐng)求。
getHandlerAdapter方法

斷點(diǎn)繼續(xù)向下分析,獲取HandlerAdapter對(duì)象都會(huì)進(jìn)入到adapter.supports(handler)函數(shù)中,基于上面的斷點(diǎn)我們可以看出SpringMVC內(nèi)部有三種HandlerAdapter,所有在最差的情況下會(huì)進(jìn)行三次adapter.supports(handler)函數(shù)中。

第一次進(jìn)入supports函數(shù)

第一次進(jìn)入的是HttpRequestHandleAdapter的suppors函數(shù),傳入的handler通過(guò) instanceof 判斷出當(dāng)前的handler不是HttpRequestHandler類(lèi)型,返回false

第一次進(jìn)入supports函數(shù)

第二次進(jìn)入supports函數(shù)

第二次進(jìn)入的是SimpleControllerHandlerAdapter的suppors函數(shù),傳入的handler通過(guò)instanceof判斷出當(dāng)前的handler不是Controller類(lèi)型,返回false

第二次進(jìn)入supports函數(shù)

第三次進(jìn)入supports函數(shù)

第三次進(jìn)入的是AbstractHandlerMethodAdapter的suppors函數(shù),傳入的handler通過(guò)instanceof判斷出當(dāng)前的handler是HandlerMethod類(lèi)型,返回true。

第三次進(jìn)入supports函數(shù)

斷點(diǎn)繼續(xù)向下,最終將HandlerAdapter返回到doDispatch函數(shù)中

doDispatch方法

實(shí)際返回的HandlerAdapter為RequestMappingHandlerAdapter,這是因?yàn)镽equestMappingHandlerAdapter繼承了AbstractHandlerMethodAdapter。

2.5.2.getHandlerAdapter源碼分析

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            for (HandlerAdapter adapter : this.handlerAdapters) {
                //判斷當(dāng)前的HandlerAdapter能否處理handler,如果能夠處理,將當(dāng)前HandlerAdapter返回
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

getHandlerAdapter函數(shù),實(shí)際上是遍歷SpringMVC內(nèi)部的HandlerAdapter,并調(diào)用HandlerAdapter的supports函數(shù)傳入handler,判斷當(dāng)前handler能否被SpringMVC內(nèi)部的HandlerAdapter處理,如果可以處理將當(dāng)前HandlerAdapter返回,如果都不能處理則拋出ServletException異常。

2.6. 核心步驟ha.handle方法剖析

  • ha.handle方法執(zhí)行的入口

    通過(guò)在ha.handle()方法加入斷點(diǎn),可以看到handle方法執(zhí)行前會(huì)找到具體的handler方法,例如在下圖的斷點(diǎn)中可以看到當(dāng)前的mappedHandler.getHandler()獲取到當(dāng)前請(qǐng)求應(yīng)該被DemoController中handle01 uri對(duì)應(yīng)的方法處理。

handle方法
  • handleInternal處理請(qǐng)求的核心方法

    斷點(diǎn)繼續(xù)向下會(huì)先進(jìn)入AbstractHandlerMethodAdapter類(lèi)中的handle方法,在handler方法中調(diào)用本類(lèi)中的抽象方法handleInternal,斷點(diǎn)繼續(xù)向下會(huì)進(jìn)入RequestMappingHandlerAdapter類(lèi)中的handleInternal方法,RequestMappingHandlerAdapter類(lèi)繼承了AbstractHandlerMethodAdapter類(lèi),并實(shí)現(xiàn)了該類(lèi)的handleInternal方法。進(jìn)入handleInternal方法首先會(huì)校驗(yàn)當(dāng)前請(qǐng)求的類(lèi)型,然后繼續(xù)向下判斷當(dāng)前請(qǐng)求是否需要支持在同一個(gè)session中處理請(qǐng)求,如果需要支持在同一個(gè)session中處理請(qǐng)求,就會(huì)為當(dāng)前session生成一個(gè)唯一的可以用于鎖定的key,對(duì)當(dāng)前請(qǐng)求進(jìn)行加鎖。無(wú)論是否需要支持在同一個(gè)session中處理請(qǐng)求,最終都會(huì)調(diào)用invokeHandlerMethod函數(shù),實(shí)現(xiàn)請(qǐng)求處理,并將處理結(jié)果封裝到ModelAndView中。

handleInternal方法
  • RequestMappingHandlerAdapter中的invokeHandlerMethod執(zhí)行流程

    invokeHandlerMethod首先會(huì)執(zhí)行g(shù)etDataBinderFactory方法,從容器中獲取全局配置的InitBinder和Controller中配置的InitBinder返回WebDataBinderFactory對(duì)象。緊接著執(zhí)行g(shù)etModelFactory方法,從容器中獲取全局配置的ModelAttribute和當(dāng)前Controller中配置的ModelAttribute返回ModelFactory。繼續(xù)執(zhí)行createInvocableHandlerMethod方法將當(dāng)前handlerMethod封裝成一個(gè)可被調(diào)用的ServletInvocableHandlerMethod對(duì)象。通過(guò)setHandlerMethodArgumentResolvers方法、setHandlerMethodReturnValueHandlers方法與setDataBinderFactory方法,分別將請(qǐng)求參數(shù)解析器、返回值解析器與ModelFactory,設(shè)置到ServletInvocableHandlerMethod中。接著通過(guò)new ModelAndViewContainer()實(shí)例化ModelAndViewContainer容器,并向容器中添加request屬性。通過(guò)ModelFactory調(diào)用initModel方法,從而達(dá)到@ModelAttribute標(biāo)注的方法能夠在目標(biāo)Handler調(diào)用之前調(diào)用的目的。繼續(xù)調(diào)用WebAsyncUtils.createAsyncWebRequest將當(dāng)前請(qǐng)求設(shè)置為異步請(qǐng)求。最終通過(guò)ServletInvocableHandlerMethod調(diào)用invokeAndHandle方法,對(duì)請(qǐng)求參數(shù)進(jìn)行處理,調(diào)用目標(biāo)HandlerMethod,并且將返回值封裝為一個(gè)ModelAndView對(duì)象。返回ModelAndView對(duì)象后,會(huì)繼續(xù)調(diào)用getModelAndView方法對(duì)封裝的ModelAndView進(jìn)行處理,主要是判斷當(dāng)前請(qǐng)求是否進(jìn)行了重定向,如果進(jìn)行了重定向,還會(huì)判斷是否需要將FlashAttributes封裝到新的請(qǐng)求中,并將ModelAndView對(duì)象返回。

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
      // 獲取容器中全局配置的InitBinder和當(dāng)前HandlerMethod所對(duì)應(yīng)的Controller中配置的InitBinder注解,用于進(jìn)行參數(shù)的綁定,例如時(shí)間格式轉(zhuǎn)換
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      // 獲取容器中全局配置的ModelAttribute和當(dāng)前當(dāng)前HandlerMethod所對(duì)應(yīng)的Controller中配置的ModelAttribute,這些配置的方法將會(huì)在目標(biāo)方法調(diào)用之前進(jìn)行調(diào)用
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

      // 將handlerMethod封裝為一個(gè)ServletInvocableHandlerMethod對(duì)象,封裝成一個(gè)可被調(diào)用的invocableHandlerMethod
      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      if (this.argumentResolvers != null) {
         // 設(shè)置當(dāng)前容器中配置的所有ArgumentResolver,設(shè)置請(qǐng)求參數(shù)解析器
         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      if (this.returnValueHandlers != null) {
         // 設(shè)置當(dāng)前容器中配置的所有ReturnValueHandler,設(shè)置返回值解析器
         invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      }
      // 將前面創(chuàng)建的WebDataBinderFactory設(shè)置到ServletInvocableHandlerMethod中
      invocableMethod.setDataBinderFactory(binderFactory);

      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
      //實(shí)例化ModelAndViewContainer對(duì)象
      ModelAndViewContainer mavContainer = new ModelAndViewContainer();
      //向ModleAndViewContainer容器中添加request屬性
      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
      // 這里initModel()方法主要作用是調(diào)用前面獲取到的@ModelAttribute標(biāo)注的方法,
      // 從而達(dá)到@ModelAttribute標(biāo)注的方法能夠在目標(biāo)Handler調(diào)用之前調(diào)用的目的
      modelFactory.initModel(webRequest, mavContainer, invocableMethod);
      mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
      //設(shè)置異步請(qǐng)求處理
      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
      asyncWebRequest.setTimeout(this.asyncRequestTimeout);

      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      asyncManager.setTaskExecutor(this.taskExecutor);
      asyncManager.setAsyncWebRequest(asyncWebRequest);
      asyncManager.registerCallableInterceptors(this.callableInterceptors);
      asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

      if (asyncManager.hasConcurrentResult()) {
         Object result = asyncManager.getConcurrentResult();
         mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
         asyncManager.clearConcurrentResult();
         LogFormatUtils.traceDebug(logger, traceOn -> {
            String formatted = LogFormatUtils.formatValue(result, !traceOn);
            return "Resume with async result [" + formatted + "]";
         });
         invocableMethod = invocableMethod.wrapConcurrentResult(result);
      }

      // 對(duì)請(qǐng)求參數(shù)進(jìn)行處理,調(diào)用目標(biāo)HandlerMethod,并且將返回值封裝為一個(gè)ModelAndView對(duì)象
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
      }

      // 對(duì)封裝的ModelAndView進(jìn)行處理,主要是判斷當(dāng)前請(qǐng)求是否進(jìn)行了重定向,如果進(jìn)行了重定向,
      // 還會(huì)判斷是否需要將FlashAttributes封裝到新的請(qǐng)求中
      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}
  • ServletInvocableHandlerMethod中的invokeAndHandle方法

    斷點(diǎn)繼續(xù)向下,就會(huì)執(zhí)行到ServletInvocableHandlerMethod中的invokeAndHandle方法,在invokeAndHandle方法中,核心調(diào)用了InvocableHandlerMethod中的invokeForRequest方法,處理請(qǐng)求參數(shù)中的并調(diào)用調(diào)用目標(biāo)handler

    invokeAndHandle方法
  • InvocableHandlerMethod中的invokeForRequest方法

    invokeForRequest方法的核心主要有兩個(gè),先調(diào)用getMethodArgumentValues方法將request中的參數(shù)轉(zhuǎn)換成當(dāng)前handler的參數(shù)形式。最終通過(guò)doInvoke()方法主要是結(jié)合處理后的參數(shù),使用反射對(duì)目標(biāo)方法進(jìn)行調(diào)用

    invokeForRequest方法

2.7. 頁(yè)面渲染processDispatchResult方法剖析

  • processDispatchResult方法首先會(huì)判斷是否需要處理異常信息,緊接著調(diào)用核心方法render,實(shí)現(xiàn)頁(yè)面視圖渲染。
processDispatchResult方法
  • render方法先定義了一個(gè)view對(duì)象,核心調(diào)用resolveViewName獲取view對(duì)象。
render方法
  • resolveViewName方法中主要獲取了springmvc.xml配置的視圖解析器,通過(guò)試圖解析器調(diào)用viewResoler.resolveViewName方法,獲取View視圖
resolveViewName方法
  • 視圖解析器中調(diào)用resolveViewName方法,首先會(huì)嘗試從緩存中獲取視圖,如果緩存中沒(méi)有就會(huì)調(diào)用createView創(chuàng)建視圖

    視圖解析器resolveViewName
  • createView方法會(huì)先判斷當(dāng)前返回的視圖類(lèi)型是否為重定向類(lèi)型或?yàn)檗D(zhuǎn)發(fā)類(lèi)型,如果以上都不是繼續(xù)調(diào)用父類(lèi)的createView方法。
createView方法
  • 斷點(diǎn)繼續(xù)向下,先進(jìn)入AbstractCachingViewResolver類(lèi)中的createView方法,在createView方法中調(diào)用loadView。進(jìn)入loadView方法,會(huì)調(diào)用到UrlBasedViewResolver類(lèi)中的loadView方法,loadView方法內(nèi)部會(huì)先調(diào)用buildView創(chuàng)建一個(gè)AbstractUrlBasedView。
AbstractCachingViewResolver中的createView
  • 斷點(diǎn)繼續(xù)向下,進(jìn)入InternalResourceViewResolver中的buildView方法,buildView方法核心調(diào)用父類(lèi)的buildView方法;

    buildView方法
  • 斷點(diǎn)繼續(xù)向下,在UrlBasedViewResolver類(lèi)中的bulidView方法中,會(huì)將邏輯視圖名轉(zhuǎn)換成物理視圖名

    bulidView方法
  • 創(chuàng)建完View對(duì)象后,回到DispatcherServlet中的render方法,render方法獲取到view視圖后,通過(guò)view視圖調(diào)用render方法,封裝數(shù)據(jù);

    render方法
  • 斷點(diǎn)繼續(xù)向下,進(jìn)入AbstractView類(lèi)中的render方法,調(diào)用createMergedOutputModel方法獲取返回頁(yè)面的數(shù)據(jù),并調(diào)用renderMergedOutputModel進(jìn)行數(shù)據(jù)線渲染;

    AbstractView類(lèi)中的render方法
  • 斷點(diǎn)繼續(xù)向下,進(jìn)入到InternalResourceView類(lèi)中的renderMergedOutputModel方法,在此方法中主要調(diào)用了exposeModelAsRequestAttributes
renderMergedOutputModel方法
  • 在exposeModelAsRequestAttributes方法中,會(huì)將數(shù)據(jù)設(shè)置到請(qǐng)求的域中。這也是為什么后臺(tái)model.add之后在jsp中可以從請(qǐng)求 域取出來(lái)的根本原因。

    exposeModelAsRequestAttributes方法
  • 最終調(diào)用RequestDispatcher中的forward方法,跳轉(zhuǎn)到success頁(yè)面

    forward方法

3. SpringMVC九大組件初始化

3.1 SpringMVC中的九大組件

DispatcherServlet中定義了九個(gè)屬性,每一種屬性都對(duì)應(yīng)了一個(gè)組件

    /** MultipartResolver used by this servlet. */
    //多部件解析器,一般用于文件上傳
    @Nullable
    private MultipartResolver multipartResolver;

    /** LocaleResolver used by this servlet. */
    //區(qū)域化,國(guó)際化相關(guān)
    @Nullable
    private LocaleResolver localeResolver;

    /** ThemeResolver used by this servlet. */
    //主題解析器
    @Nullable
    private ThemeResolver themeResolver;

    /** List of HandlerMappings used by this servlet. */
    //處理器映射器組件
    @Nullable
    private List<HandlerMapping> handlerMappings;

    /** List of HandlerAdapters used by this servlet. */
    //處理器適配器組件
    @Nullable
    private List<HandlerAdapter> handlerAdapters;

    /** List of HandlerExceptionResolvers used by this servlet. */
    //異常解析器組件
    @Nullable
    private List<HandlerExceptionResolver> handlerExceptionResolvers;

    /** RequestToViewNameTranslator used by this servlet. */
    //默認(rèn)的視圖名轉(zhuǎn)換器組件
    @Nullable
    private RequestToViewNameTranslator viewNameTranslator;

    /** FlashMapManager used by this servlet. */
    //flash屬性管理組件
    @Nullable
    private FlashMapManager flashMapManager;

    /** List of ViewResolvers used by this servlet. */
    //視圖解析器組件
    @Nullable
    private List<ViewResolver> viewResolvers;

九大組件都是定義了接口,接口其實(shí)就是定義了該組件的規(guī)范,比如ViewResolver、HandlerAdapter等都是接口

3.2. 九大組件初始化時(shí)機(jī)

  • DispatcherServlet中的onRefresh()方法,該方法初始化了SpringMVC的九大組件

    onRefresh()方法只調(diào)用了initStrategies(context)函數(shù),可以明確九大組件初始化是在initStrategies函數(shù)中完成的

    @Override
    protected void onRefresh(ApplicationContext context) {
        // 初始化策略
        initStrategies(context);
    }
  • initStrategies方法

    在initStrategies函數(shù)中,依次對(duì)springMVC九大組件進(jìn)行了初始化。挑取幾個(gè)重要的初始化函數(shù)進(jìn)行后續(xù)分析,例如:initHandlerMappings

protected void initStrategies(ApplicationContext context) {
   // 多文件上傳的組件
   initMultipartResolver(context);
   // 初始化本地語(yǔ)言環(huán)境
   initLocaleResolver(context);
   // 初始化模板處理器
   initThemeResolver(context);
   // 初始化HandlerMapping
   initHandlerMappings(context);
   // 初始化參數(shù)適配器
   initHandlerAdapters(context);
   // 初始化異常攔截器
   initHandlerExceptionResolvers(context);
   // 初始化視圖預(yù)處理器
   initRequestToViewNameTranslator(context);
   // 初始化視圖轉(zhuǎn)換器
   initViewResolvers(context);
   // 初始化 FlashMap 管理器
   initFlashMapManager(context);
}
  • 分析其中的一個(gè)組件initHandlerMappings(context)
  1. 由于detectAllHandlerMappings的默認(rèn)值為true,所以會(huì)先進(jìn)入IOC容器中,按照HandlerMapping類(lèi)型去找到所有的HandlerMapping;
  2. 如果按照類(lèi)型沒(méi)有在IOC容器中找到,繼續(xù)按照id(handlerMapping)在IOC容器中查找;
  3. 若是以上兩種方式都沒(méi)在IOC容器中找到,就會(huì)按照默認(rèn)的策略生成HandlerMapping。
private void initHandlerMappings(ApplicationContext context) {
   this.handlerMappings = null;

   if (this.detectAllHandlerMappings) {
      // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
      // 按照HandlerMapping類(lèi)型去IOC容器中找到所有的HandlerMapping
      Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
      if (!matchingBeans.isEmpty()) {
         this.handlerMappings = new ArrayList<>(matchingBeans.values());
         // We keep HandlerMappings in sorted order.
         AnnotationAwareOrderComparator.sort(this.handlerMappings);
      }
   }
   else {
      try {
         // 否則在ioc中按照固定名稱(chēng)id(handlerMapping)去找
         HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
         this.handlerMappings = Collections.singletonList(hm);
      }
      catch (NoSuchBeanDefinitionException ex) {
         // Ignore, we'll add a default HandlerMapping later.
      }
   }

   // Ensure we have at least one HandlerMapping, by registering
   // a default HandlerMapping if no other mappings are found.
   if (this.handlerMappings == null) {
      // 最后還為空,則按照默認(rèn)策略生成HandlerMapping
      this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
      if (logger.isTraceEnabled()) {
         logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
               "': using default strategies from DispatcherServlet.properties");
      }
   }
}
  • 分析getDefaultStrategies默認(rèn)生成HandlerMapping的策略

    如果按照類(lèi)型和按照固定id從ioc容器中找不到對(duì)應(yīng)的組件,則會(huì)按照默認(rèn)的額策略進(jìn)行初始化,默認(rèn)策略在DispatcherServlet.properties中配置

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
   String key = strategyInterface.getName();
   //實(shí)際上獲取的是DispatcherServlet.properties中的HandlerMapping
   String value = defaultStrategies.getProperty(key);
   if (value != null) {
      String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
      List<T> strategies = new ArrayList<>(classNames.length);
      for (String className : classNames) {
         try {
            Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
            Object strategy = createDefaultStrategy(context, clazz);
            strategies.add((T) strategy);
         }
         catch (ClassNotFoundException ex) {
            throw new BeanInitializationException(
                  "Could not find DispatcherServlet's default strategy class [" + className +
                  "] for interface [" + key + "]", ex);
         }
         catch (LinkageError err) {
            throw new BeanInitializationException(
                  "Unresolvable class definition for DispatcherServlet's default strategy class [" +
                  className + "] for interface [" + key + "]", err);
         }
      }
      return strategies;
   }
   else {
      return new LinkedList<>();
   }
}

分析defaultStrategies的初始化時(shí)機(jī),發(fā)現(xiàn)defaultStrategies是在DispatcherServlet的靜態(tài)代碼塊中完成的初始化,其中 DEFAULT_STRATEGIES_PATH 對(duì)應(yīng)的就是DispatcherServlet.properties,靜態(tài)代碼塊讀取DispatcherServlet.properties中的屬性,并封裝到defaultStrategies Properties集合中。

defaultStrategies
  • DispatcherServlet.properties

    在DispatcherServlet.properties中可以看到SpringMVC默認(rèn)的兩種HandleMapping類(lèi)型的定義。默認(rèn)的三種HandlerAdapter也是在DispatcherServlet.properties中定義的,同時(shí)HandlerAdapter初始化的邏輯與HandleMapping初始化邏輯基本一致。

DispatcherServlet.properties
  • 多部件MultipartResolver文件上傳組件初始化

    SpringMVC的多部件解析器的初始化必須是按照id(multipartResolver)注冊(cè)對(duì)象

    private void initMultipartResolver(ApplicationContext context) {
       try {
          //將MULTIPART_RESOLVER_BEAN_NAME作為id注冊(cè)對(duì)象
          this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
          if (logger.isTraceEnabled()) {
             logger.trace("Detected " + this.multipartResolver);
          }
          else if (logger.isDebugEnabled()) {
             logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
          }
       }
       catch (NoSuchBeanDefinitionException ex) {
          // Default is no multipart resolver.
          this.multipartResolver = null;
          if (logger.isTraceEnabled()) {
             logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
          }
       }
    }
    

    多部件解析器的初始化id默認(rèn)是multipartResolver

multipartResolver
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容