参数解析原理

我们了解过常用参数注解(如@PathVariable、@RequestParam、@RequestHeader、@CookieValue、@RequestAttribute和@RequestBody)的使用,见常用参数注解这篇文章,想知道这些注解是怎么解析参数的,调试下跟着源码走一遍,体会会更加深刻一些。

1. DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//...
      HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
      mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    //...
}

在这里插入图片描述
可以看到处理器适配器有以下4种:

  • RequestMappingHandlerAdapter
  • HandlerFunctionAdapter
  • HttpRequestHandlerAdapter
  • SimpleControllerHandlerAdapter
2. AbstractHandlerMethodAdapter#handle
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return this.handleInternal(request, response, (HandlerMethod)handler);
}
3. RequestMappingHandlerAdapter#handleInternal
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  //...
     ModelAndView mav;
     if (this.synchronizeOnSession) {
     	//...
     } else {
         mav = this.invokeHandlerMethod(request, response, handlerMethod);
     }
//...
     return mav;
 }
4. RequestMappingHandlerAdapter#invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	//...
	Object result;
    try {
    	//...
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }

        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
		//...
		invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
		//...
    } finally {
		//...
    }

    return (ModelAndView)result;
}

可以看到,参数解析器有如下27种,
在这里插入图片描述
返回值处理器有如下15种,
在这里插入图片描述

5. ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
}
6. InvocableHandlerMethod#invokeForRequest
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }

    return this.doInvoke(args);
}
7. InvocableHandlerMethod#getMethodArgumentValues
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    MethodParameter[] parameters = this.getMethodParameters();
    if (ObjectUtils.isEmpty(parameters)) {
        return EMPTY_ARGS;
    } else {
        Object[] args = new Object[parameters.length];

        for(int i = 0; i < parameters.length; ++i) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            args[i] = findProvidedArgument(parameter, providedArgs);
            if (args[i] == null) {
                if (!this.resolvers.supportsParameter(parameter)) {
                    throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
                }

                try {
                    args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                } catch (Exception var10) {
                    if (logger.isDebugEnabled()) {
                        String exMsg = var10.getMessage();
                        if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                            logger.debug(formatArgumentError(parameter, exMsg));
                        }
                    }

                    throw var10;
                }
            }
        }

        return args;
    }
}

首先,判断参数解析器是否支持解析该参数: this.resolvers.supportsParameter(parameter)
如果支持,接下来参数解析器会解析该参数:args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory)
在这里插入图片描述

7.1 HandlerMethodArgumentResolverComposite#supportsParameter
public boolean supportsParameter(MethodParameter parameter) {
    return this.getArgumentResolver(parameter) != null;
}
7.1.1 HandlerMethodArgumentResolverComposite#getArgumentResolver
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
      HandlerMethodArgumentResolver result = (HandlerMethodArgumentResolver)this.argumentResolverCache.get(parameter);
      if (result == null) {
          Iterator var3 = this.argumentResolvers.iterator();

          while(var3.hasNext()) {
              HandlerMethodArgumentResolver resolver = (HandlerMethodArgumentResolver)var3.next();
              if (resolver.supportsParameter(parameter)) {
                  result = resolver;
                  this.argumentResolverCache.put(parameter, resolver);
                  break;
              }
          }
      }

      return result;
  }
7.2 HandlerMethodArgumentResolverComposite#resolveArgument
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
    if (resolver == null) {
        throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
    } else {
        return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    }
}

在这里插入图片描述

7.2.1 AbstractNamedValueMethodArgumentResolver#resolveArgument
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    AbstractNamedValueMethodArgumentResolver.NamedValueInfo namedValueInfo = this.getNamedValueInfo(parameter);
    MethodParameter nestedParameter = parameter.nestedIfOptional();
    Object resolvedName = this.resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
    if (resolvedName == null) {
        throw new IllegalArgumentException("Specified name must not resolve to null: [" + namedValueInfo.name + "]");
    } else {
        Object arg = this.resolveName(resolvedName.toString(), nestedParameter, webRequest);
		//...
        this.handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
        return arg;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值