RequestMappingHandlerAdapter和RequestParam原理分析 RequestMapping原理分析和RequestMappingHandlerMapping

我們要使用定義了RequestMapping方法或者類是,需要先準備好所需要的參數。如何準備參數,我們應該考慮些上面問題。

都有哪些參數需要綁定?

除了方法確定的參數,還有兩個方法的參數需要綁定,那就是當前處理器相對應註釋了@ModelAttribute和註釋了@InitBinder的方法。

參數的值的來源?

有六個參數的來源:

  1. request中相關的參數,主要包括url中的參數、post中過來body中的參數,以及請求頭包含的值;
  2. cookie中的參數
  3. session中給的參數
  4. 設置到FlashMap中的參數,這種參數用於redirect的參數傳遞
  5. SessionAttribute傳遞的參數,這類參數通過@SessionAttribute註釋傳遞
  6. 通過相應的註釋了@ModelAttribute的方法設置的參數

具體進行綁定的方法?

        參數解析使用HandlerMethodArgumentResolver類型的組件完成的,不同類型的使用不同的ArgumentResolver來解析。有的Resolver內部使用了WebDataBinder,可以通過註釋了@InitBinder的方法來初始化,註釋了@InitBinder的方法也需要綁定參數,而且也是不確定的,所以@InitBinder註釋的方法也需要ArgumentResolver來解析參數,使用的和Handler不同的一套ArgumentResolver,另外註釋了ModelAttribute的方法也需要綁定參數,使用的和Handler使用的是同一套ArgumentResolver。

1.RequestMappingHandlerAdapter

此類的主要功能:

  • 備好處理器所需要的參數(這個最難,參數的不確定性)
  • 使用處理器處理請求 (這個比較簡單,直接用反射調用handleMethod處理就可以了)
  • 處理返回值,也就是將不同類型的返回值統一處理成ModelAndView類

通過xml解析初始化過程如RequestMapping原理分析和RequestMappingHandlerMapping一般,重複部分就不在分析。

1.1RequestMappingHandlerAdapter繼承圖

上圖信息比較多,我們查找關鍵信息。可以看到這個類間接實現了HandlerAdapter接口,是HandlerAdapter類型的實例。

除此之外還實現了ApplicationContextAware和IntitalzingBean 這兩個接口。

1.2RequestMappingHandlerAdapter類源碼分析

既然RequestMappingHandlerAdapter實現了ApplicationContextAware接口,那實例化時候肯定會執行setApplicationContext方法,我們查看其實現邏輯。

    @Override
    public final void setApplicationContext(ApplicationContext context) throws BeansException {
        //isContextRequired()方法返回tru
        if (context == null && !isContextRequired()) {
            // Reset internal context state.
            this.applicationContext = null;
            this.messageSourceAccessor = null;
        }
        else if (this.applicationContext == null) {
            // Initialize with passed-in context.
            //所傳入的context如果不能被實例化,則拋出異常
            if (!requiredContextClass().isInstance(context)) {
                throw new ApplicationContextException(
                        "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
            }
            this.applicationContext = context;
            //國際化
            this.messageSourceAccessor = new MessageSourceAccessor(context);
            //初始化ApplicationContext
            initApplicationContext(context);
        }
        else {
            // Ignore reinitialization if same context passed in.
            if (this.applicationContext != context) {
                throw new ApplicationContextException(
                        "Cannot reinitialize with different application context: current one is [" +
                        this.applicationContext + "], passed-in one is [" + context + "]");
            }
        }
    }

initApplicationContext裏面主要就是初始化ServletContext,就不在去分析了

RequestMappingHandlerAdapter也實現了InitializingBean接口,當設置完屬性後肯定會回調afterPropertiesSet方法,我們重點分析一下afterPropertiesSet的方法,它的源碼內容如下,下面我們一點一點的分析這個類:

    @Override
    public void afterPropertiesSet() {
        // Do this first, it may add ResponseBody advice beans
        //初始化註釋了@ControllerAdvice的類,分別用於緩存@ControllerAdvice註釋的類裏面註釋了@ModelAttribute和@InitBinder方法,也就是全局的@ModelAttribute和InitBinder方法。
        initControllerAdviceCache();

        if (this.argumentResolvers == null) {
            //初始化argumentResolvers,用於處理器方法和註釋了@ModelAttribute的方法設置參數
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.initBinderArgumentResolvers == null) {
            //初始化initBinderArgumentResolvers,用於給註釋了@initBinder的方法設置參數,使用得較少
            List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.returnValueHandlers == null) {
            //初始化returnValueHandlers,用於將處理器的返回值處理爲ModelAndView的類型
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
    }

我們先看initControllerAdviceCache這個方法:

    private void initControllerAdviceCache() {
        if (getApplicationContext() == null) {
            return;
        }
        if (logger.isInfoEnabled()) {
            logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
        }

        //獲取到所有註釋了@ControllerAdvice的bean
        List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
        //對獲取到的ControllerAdvice註解的類進行排序,排序的規則是基於實現PriorityOrdered接口或者帶有Order註解
        AnnotationAwareOrderComparator.sort(beans);

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

        for (ControllerAdviceBean bean : beans) {
            //查找註釋了@ModelAttribute而且沒有註釋@RequestMapping的方法
            Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
            if (!attrMethods.isEmpty()) {
                this.modelAttributeAdviceCache.put(bean, attrMethods);
                if (logger.isInfoEnabled()) {
                    logger.info("Detected @ModelAttribute methods in " + bean);
                }
            }
            //獲取所有帶InitBinder註解的方法
            Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
            if (!binderMethods.isEmpty()) {
                this.initBinderAdviceCache.put(bean, binderMethods);
                if (logger.isInfoEnabled()) {
                    logger.info("Detected @InitBinder methods in " + bean);
                }
            }
            //如果實現了RequestBodyAdvice接口
            if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                requestResponseBodyAdviceBeans.add(bean);
                if (logger.isInfoEnabled()) {
                    logger.info("Detected RequestBodyAdvice bean in " + bean);
                }
            }
            //如果實現了ResponseBodyAdvice接口
            if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                requestResponseBodyAdviceBeans.add(bean);
                if (logger.isInfoEnabled()) {
                    logger.info("Detected ResponseBodyAdvice bean in " + bean);
                }
            }
        }

        // 將實現了RequestBodyAdvice和ResponseBodyAdvice接口的類放入requestResponseBodyAdviceBeans
        // 這裏是放入頂部,說明通過@@ControllerAdvice註解實現接口的處理優先級最高
        if (!requestResponseBodyAdviceBeans.isEmpty()) {
            this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
        }
    }

看getDefaultArgumentResolvers主要作用是解析傳入的參數: 

// 獲取默認的 HandlerMethodArgumentResolver
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { 
    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
    // 1.基於註解的參數解析 <-- 解析的數據來源主要是 HttpServletRequest | ModelAndViewContainer
    // Annotation-based argument resolution
    // 解析被註解 @RequestParam, @RequestPart 修飾的參數, 數據的獲取通過 HttpServletRequest.getParameterValues
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    // 解析被註解 @RequestParam 修飾, 且類型是 Map 的參數, 數據的獲取通過 HttpServletRequest.getParameterMap
    resolvers.add(new RequestParamMapMethodArgumentResolver());
    // 解析被註解 @PathVariable 修飾, 數據的獲取通過 uriTemplateVars, 而 uriTemplateVars 卻是通過 RequestMappingInfoHandlerMapping.handleMatch 生成, 其實就是 uri 中映射出的 key <-> value
    resolvers.add(new PathVariableMethodArgumentResolver());
    // 解析被註解 @PathVariable 修飾 且數據類型是 Map, 數據的獲取通過 uriTemplateVars, 而 uriTemplateVars 卻是通過 RequestMappingInfoHandlerMapping.handleMatch 生成, 其實就是 uri 中映射出的 key <-> value
    resolvers.add(new PathVariableMapMethodArgumentResolver());
    // 解析被註解 @MatrixVariable 修飾, 數據的獲取通過 URI提取了;後存儲的 uri template 變量值
    resolvers.add(new MatrixVariableMethodArgumentResolver());
    // 解析被註解 @MatrixVariable 修飾 且數據類型是 Map, 數據的獲取通過 URI提取了;後存儲的 uri template 變量值
    resolvers.add(new MatrixVariableMapMethodArgumentResolver());
    // 解析被註解 @ModelAttribute 修飾, 且類型是 Map 的參數, 數據的獲取通過 ModelAndViewContainer 獲取, 通過 DataBinder 進行綁定
    resolvers.add(new ServletModelAttributeMethodProcessor(false));
    // 解析被註解 @RequestBody 修飾的參數, 以及被@ResponseBody修飾的返回值, 數據的獲取通過 HttpServletRequest 獲取, 根據 MediaType通過HttpMessageConverter轉換成對應的格式, 在處理返回值時 也是通過 MediaType 選擇合適HttpMessageConverter, 進行轉換格式, 並輸出
    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    // 解析被註解 @RequestPart 修飾, 數據的獲取通過 HttpServletRequest.getParts()
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
    // 解析被註解 @RequestHeader 修飾, 數據的獲取通過 HttpServletRequest.getHeaderValues()
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    // 解析被註解 @RequestHeader 修飾且參數類型是 Map, 數據的獲取通過 HttpServletRequest.getHeaderValues()
    resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    // 解析被註解 @CookieValue 修飾, 數據的獲取通過 HttpServletRequest.getCookies()
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    // 解析被註解 @Value 修飾, 數據在這裏沒有解析
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
    // 解析被註解 @SessionAttribute 修飾, 數據的獲取通過 HttpServletRequest.getAttribute(name, RequestAttributes.SCOPE_SESSION)
    resolvers.add(new SessionAttributeMethodArgumentResolver());
    // 解析被註解 @RequestAttribute 修飾, 數據的獲取通過 HttpServletRequest.getAttribute(name, RequestAttributes.SCOPE_REQUEST)
    resolvers.add(new RequestAttributeMethodArgumentResolver());

    // 2.基於類型的參數解析器
    // Type-based argument resolution
    // 解析固定類型參數(比如: ServletRequest, HttpSession, InputStream 等), 參數的數據獲取還是通過 HttpServletRequest
    resolvers.add(new ServletRequestMethodArgumentResolver());
    // 解析固定類型參數(比如: ServletResponse, OutputStream等), 參數的數據獲取還是通過 HttpServletResponse
    resolvers.add(new ServletResponseMethodArgumentResolver());
    // 解析固定類型參數(比如: HttpEntity, RequestEntity 等), 參數的數據獲取還是通過 HttpServletRequest
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    // 解析固定類型參數(比如: RedirectAttributes), 參數的數據獲取還是通過 HttpServletResponse
    resolvers.add(new RedirectAttributesMethodArgumentResolver());
    // 解析固定類型參數(比如: Model等), 參數的數據獲取通過 ModelAndViewContainer
    resolvers.add(new ModelMethodProcessor());
    // 解析固定類型參數(比如: Model等), 參數的數據獲取通過 ModelAndViewContainer
    resolvers.add(new MapMethodProcessor());
    // 解析固定類型參數(比如: Errors), 參數的數據獲取通過 ModelAndViewContainer
    resolvers.add(new ErrorsMethodArgumentResolver());
    // 解析固定類型參數(比如: SessionStatus), 參數的數據獲取通過 ModelAndViewContainer
    resolvers.add(new SessionStatusMethodArgumentResolver());
    // 解析固定類型參數(比如: UriComponentsBuilder), 參數的數據獲取通過 HttpServletRequest
    resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
    // 3.自定義參數解析器
    // Custom arguments
    if (getCustomArgumentResolvers() != null) {
        resolvers.addAll(getCustomArgumentResolvers());
    }
    // Catch-all
    //這兩個解析器可以解析所有類型的參數
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    resolvers.add(new ServletModelAttributeMethodProcessor(true));
    return resolvers;
}

getDefaultArgumentResolvers中有四類解析器:

  1. 基於註解的參數解析器
  2. 基於類型的參數解析器
  3. 自定義參數解析器
  4. 可解析所有類型的解析器

從源碼中可以看出,自定義的解析器是在前面兩種都無法解析是纔會使用到,這個順序是無法改變的,例如如果想自己寫一個解析器來解析@PathVariable註釋的PathVariable參數,是無法實現的,即使寫出來並註冊到RequestMappingHanderAdapter中也不會被調用

getDefaultInitBinderArgumentResolvers用得較少,原理也是類似的,就不分析了。

分析getDefaultReturnValueHandlers方法:

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
    List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();

    // Single-purpose return value types
    // 支持 ModelAndView 類型的 HandlerMethodReturnValueHandler, 最後將數據寫入 ModelAndViewContainer
    handlers.add(new ModelAndViewMethodReturnValueHandler());
    // 支持 Map 類型的 HandlerMethodReturnValueHandler, 最後將數據寫入 ModelAndViewContainer
    handlers.add(new ModelMethodProcessor());
    // 支持 View 類型的 HandlerMethodReturnValueHandler, 最後將數據寫入 ModelAndViewContainer
    handlers.add(new ViewMethodReturnValueHandler());
    // 支持 ResponseEntity 類型的 HandlerMethodReturnValueHandler, 最後將數據寫入 HttpServletResponse 的數據流中 OutputStream
    handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
    // 支持 ResponseEntity | StreamingResponseBody 類型的 HandlerMethodReturnValueHandler, 最後將數據寫入 HttpServletResponse 的數據流中 OutputStream
    handlers.add(new StreamingResponseBodyReturnValueHandler());
    // 支持 HttpEntity | !RequestEntity 類型的 HandlerMethodReturnValueHandler, 最後將數據寫入 HttpServletResponse 的數據流中 OutputStream
    handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));
    // 支持 HttpHeaders 類型的 HandlerMethodReturnValueHandler, 最後將數據寫入 HttpServletResponse 的數據頭部
    handlers.add(new HttpHeadersReturnValueHandler());
    // 支持 Callable 類型的 HandlerMethodReturnValueHandler
    handlers.add(new CallableMethodReturnValueHandler());
    handlers.add(new DeferredResultMethodReturnValueHandler());
    // 支持 WebAsyncTask 類型的 HandlerMethodReturnValueHandler
    handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

    // Annotation-based return value types
    // 將數據加入 ModelAndViewContainer 的 HandlerMethodReturnValueHandler
    handlers.add(new ModelAttributeMethodProcessor(false));
    // 返回值被 ResponseBody 修飾的返回值, 並且根據 MediaType 通過 HttpMessageConverter 轉化後進行寫入數據流中
    handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));

    // Multi-purpose return value types
    // 支持返回值爲 CharSequence 類型, 設置 ModelAndViewContainer.setViewName
    handlers.add(new ViewNameMethodReturnValueHandler());
    // 支持返回值爲 Map, 並將結果設置到 ModelAndViewContainer
    handlers.add(new MapMethodProcessor());
    // Custom return value types
    if (getCustomReturnValueHandlers() != null) {
        handlers.addAll(getCustomReturnValueHandlers());
    }
    // Catch-all
    if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
        handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
    }
    else {
        handlers.add(new ModelAttributeMethodProcessor(true));
    }
    return handlers;
}

在這裏就初始化完成了,有了這些工具類後我們就可以對收到請求的參數和處理後返回不同的類型進行處理了。

DispatchServlet繼承自Servlet,那所有的請求都會在service()方法中進行處理。最後在DispatcherServlet#doDispatch中處理請求後。根據不同的請求會找到對應的HandlerMapping,然後在找到HandlerAdapter進行處理。

如果處理的HandlerAdapter是RequestMappingHandlerAdapter,最後會走到RequestMappingHandlerAdapter#handleInternal:

    @Override
    protected ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
            ......
            mav = invokeHandlerMethod(request, response, handlerMethod);
            ......
    }

進入invokeHandlerMethod:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    // 構建 ServletWebRequest <-- 主要由 HttpServletRequest, HttpServletResponse
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // 構建 DataBinder 工廠
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // binderFactory 中存儲着被 @InitBinder, @ModelAttribute 修飾的方法 <- 最終包裹成 InvocableHandlerMethod
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        // 構建一個 ServletInvocableHandlerMethod
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        // 設置方法參數解析器 HandlerMethodArgumentValueResolver
        invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        // 返回值處理器 HandlerMethodReturnValueHandler
        invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        // 設置 WebDataBinderFactory
        invocableMethod.setDataBinderFactory(binderFactory);
        // 設置 參數名解析器
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        // 獲取 HttpServletRequest 中存儲的 FlashMap
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        // 這裏是激活 @ModelAttribute, @InitBinder 方法, 並將返回值放入 ModelAndViewContainer
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
        // 將 HttpServletRequest 轉換成方法的參數, 激活方法, 最後 通過 HandlerMethodReturnValueHandler 來處理返回值
        invocableMethod.invokeAndHandle(webRequest, mavContainer);      
        // 生成 ModelAndView
        return getModelAndView(mavContainer, modelFactory, webRequest); 
    }
    finally {
        webRequest.requestCompleted(); // 標誌請求已經結束, 進行一些生命週期回調函數的激活
    }
}

在上面的代碼中我們創建了一個ServletInvocableHandlerMethod對象,在這個對象中設置了參數解析器、返回值處理器、數據校驗工廠類等。接着我們進入到invocableMethod.invokeAndHandle這個方法中看一下:

    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        ......
    }

在invokeForRequest這個方法中,主要乾了兩件事,一是解析請求參數,二是調用Controller中的請求方法。這裏我們主要關注的是參數解析的部分:

    public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        //解析請求參數
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                    "' with arguments " + Arrays.toString(args));
        }
        //調用Controller中的請求方法
        Object returnValue = doInvoke(args);
        if (logger.isTraceEnabled()) {
            logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                    "] returned [" + returnValue + "]");
        }
        return returnValue;
    }

進入getMethodArgumentValues:

    private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        //這裏的 getMethodParameters 其實是在構造 MethodParameters 時創建的
        MethodParameter[] parameters = getMethodParameters();
        Object[] args = new Object[parameters.length];
        //從這裏開始對參數進行一個一個解析 <- 主要是通過 HandlerMethodArgumentResolver
        for (int i = 0; i < parameters.length; i++) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            //如果之前有預先設置值的話,則取預先設置好的值
            args[i] = resolveProvidedArgument(parameter, providedArgs);
            if (args[i] != null) {
                continue;
            }
            //獲取能解析出方法參數值的參數解析器類
            if (this.argumentResolvers.supportsParameter(parameter)) {
                try {
                    //通過 argumentResolvers 解析 HandlerMethod 裏面對應的參數內容
                    args[i] = this.argumentResolvers.resolveArgument(
                            parameter, mavContainer, request, this.dataBinderFactory);
                    continue;
                }
                catch (Exception ex) {
                    if (logger.isDebugEnabled()) {
                        logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
                    }
                    throw ex;
                }
            }
            //如果沒有能解析方法參數的類,拋出異常
            if (args[i] == null) {
                throw new IllegalStateException("Could not resolve method parameter at index " +
                        parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
                        ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
            }
        }
        return args;
    }

這裏需要說的是argumentResolvers這個對象是HandlerMethodArgumentResolverComposite這個類。所有參數的解析都是委託這個類來完成的,這個類會調用真正的請求參數的解析的類:

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return (getArgumentResolver(parameter) != null);
    }
    private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
        //先看之前有沒有解析過這個方法參數,如果解析過,則從緩存中取
        HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
        if (result == null) {
            //循環所有的參數解析類,匹配真正參數解析的類
            for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
                            parameter.getGenericParameterType() + "]");
                }
                if (methodArgumentResolver.supportsParameter(parameter)) {
                    result = methodArgumentResolver;
                    //放到緩存中
                    this.argumentResolverCache.put(parameter, result);
                    break;
                }
            }
        }
        return result;
    }

下一篇分析具體從URL參數中傳的值,如何綁定到對應controller參數上面。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章