Spring MVC 源碼分析之 請(qǐng)求參數(shù)解析

一、前言

在前面幾篇文章分析了請(qǐng)求轉(zhuǎn)發(fā)、Controller查找及攔截器的加載等信息,那么當(dāng)帶有參數(shù)的請(qǐng)求發(fā)送到服務(wù)端,SpringMVC又是怎樣把請(qǐng)求參數(shù),分析轉(zhuǎn)換后傳入到對(duì)應(yīng)的方法中的呢?本篇文章主要分析請(qǐng)求參數(shù)的解析、類型轉(zhuǎn)換及數(shù)據(jù)的綁定。

二、請(qǐng)求執(zhí)行者適配器

再次分析DispatcherServlet 中的 doDispatch方法發(fā)現(xiàn),在獲取到 Handler后會(huì)再次跟進(jìn)Handler的找到執(zhí)行此handler的適配器。如所示:

image
image.gif

?

1、查看HandlerAdapter接口的方法列表

public interface HandlerAdapter {

    boolean supports(Object handler);

    @Nullable
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    long getLastModified(HttpServletRequest request, Object handler);

}

image.gif

說明:

此處主要關(guān)心 supports方法,此方法是返回此適配器是否支持執(zhí)行對(duì)應(yīng)handler。上文分析的所有的 Controller 解析成的Handler是通過適配器 RequestMappingHandlerAdapter 處理的,接下來(lái)將分析 次實(shí)現(xiàn)了。

2、適配器 RequestMappingHandlerAdapter 繼承關(guān)系

image
image.gif

?

3、初始化

RequestMappingHandlerAdapter實(shí)現(xiàn)了 InitializingBean 接口,屬性Spring 接口的都知道,此接口只有一個(gè)方法 afterPropertiesSet(),是在類初始化完成后調(diào)用的方法。那么接下來(lái)咱們看看此類中afterPropertiesSet() 方法的具體實(shí)現(xiàn)。

public void afterPropertiesSet() {
        // 初始化 加了注解 @ControllerAdvice 的類的屬性信息
        initControllerAdviceCache();

  //主要實(shí)現(xiàn)三個(gè)變量  argumentResolvers initBinderArgumentResolvers  returnValueHandlers
        if (this.argumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.initBinderArgumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.returnValueHandlers == null) {
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
    }
image.gif

接著再看看 initControllerAdviceCace 方法的具體實(shí)現(xiàn)

private void initControllerAdviceCache() {
        if (getApplicationContext() == null) {
            return;
        }

        // 在Spring容器中獲取所有加了注解 @ControllerAdvice 的類
        List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());

        List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();

        for (ControllerAdviceBean adviceBean : adviceBeans) {
            Class<?> beanType = adviceBean.getBeanType();
            if (beanType == null) {
                throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
            }
//在當(dāng)前類中獲取所有添加了注解 @ModelAttribute 且沒有添加 注解@RequestMapping的方法,并且添加到緩存中。
            Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
            if (!attrMethods.isEmpty()) {
                this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
            }
////在當(dāng)前類中獲取所有添加了注解 @InitBinder的方法,并且添加到緩存中。
            Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
            if (!binderMethods.isEmpty()) {
                this.initBinderAdviceCache.put(adviceBean, binderMethods);
            }
//判斷是否實(shí)現(xiàn)了 接口 RequestBodyAdvice
            if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
                requestResponseBodyAdviceBeans.add(adviceBean);
            }
        }

        if (!requestResponseBodyAdviceBeans.isEmpty()) {
            this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
        }

    }
image.gif

4、handle 處理方法

RequestMappingHandlerAdapter類的handle方法是在其父類中實(shí)現(xiàn)的,但在父類中只是調(diào)用了模板方法 handleInternal ,handleInternal方法又有具體的子類進(jìn)行實(shí)現(xiàn),那么接下來(lái)在分析一下 handleInternal 方法。

@Override
    protected ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ModelAndView mav;
//檢測(cè)方法給定的Request是否支持 且是否要求 session。
        checkRequest(request);

        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
           // 省略 同步Session調(diào)用
        }
        else {
            // No synchronization on session demanded at all...
            //主要方法
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }

        if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
            if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            }
            else {
                prepareResponse(response);
            }
        }

        return mav;
    }
image.gif

此種的重點(diǎn)方法為 invokeHandlerMethod 此方法較為復(fù)雜,接下來(lái)主要分析一下此方法。

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

        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            if (this.argumentResolvers != null) {
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            }
            if (this.returnValueHandlers != null) {
                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            }
            invocableMethod.setDataBinderFactory(binderFactory);
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

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

            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }

            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }
image.gif

此方法的功能分析:

1)、首先使用request和response創(chuàng)建了ServletWebRequest類型的webRequest,在ArgumentResolver解析參數(shù)時(shí)使用的request就是這個(gè)webRequest,當(dāng)然如果我們的處理器需要HttpServletRequest類型的參數(shù),ArgumentResolver會(huì)給我們?cè)O(shè)置原始的request。

2)、接著對(duì)WebDataBinderFactory、ModelFactory、ServletInvocableHandlerMethod這三個(gè)類型的變量進(jìn)行了定義和初始化,下面先分別介紹一下這三個(gè)變量。

對(duì)三個(gè)變量的解析:

  • WebDataBinderFactory 的作用從名字就可以看出是用來(lái)創(chuàng)建WebDataBinder的,WebDataBinder用于參數(shù)綁定,主要功能就是實(shí)現(xiàn)參數(shù)跟String之間的類型轉(zhuǎn)換,ArgumentResolver在進(jìn)行參數(shù)解析的過程中會(huì)用到WebDataBinder,另外ModelFactory在更新Model時(shí)也會(huì)用到它。
  • ModelFactory是用來(lái)處理Model的,主要包含兩個(gè)功能:①在處理器具體處理之前對(duì)Model進(jìn)行初始化;②在處理完請(qǐng)求后對(duì)Model參數(shù)進(jìn)行更新。
  • ServletInvocableHandlerMethod 類型非常重要,它繼承自HandlerMethod,并且可以直接執(zhí)行。實(shí)際請(qǐng)求的處理就是通過它來(lái)執(zhí)行的,參數(shù)綁定、處理請(qǐng)求以及返回值處理都在它里邊完成。
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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