SpringMVC源码分析(三)之Controller方法参数的工作原理


         前一篇博客中,我们分析了springMVC对请求地址解析以及转发执行的原理过程,本节将重点分析下Controller方法中参数的工作原理


         分析入口依然是上一篇中提到的 ServletInvocableHandlerMethod 类的 invokeAndHandle方法:


       我们知道在创建该handlerMethod实例时候,我们设置了相应的 resolver 与handlers


      argumentResovlers 与 returnValueHandlers 在afterPropertiesSet中设置

其中默认的argumentResolvers:

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
   List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

   // Annotation-based argument resolution
   resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
   resolvers.add(new RequestParamMapMethodArgumentResolver());
   resolvers.add(new PathVariableMethodArgumentResolver());
   resolvers.add(new PathVariableMapMethodArgumentResolver());
   resolvers.add(new MatrixVariableMethodArgumentResolver());
   resolvers.add(new MatrixVariableMapMethodArgumentResolver());
   resolvers.add(new ServletModelAttributeMethodProcessor(false));
   resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
   resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
   resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
   resolvers.add(new RequestHeaderMapMethodArgumentResolver());
   resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
   resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

   // Type-based argument resolution
   resolvers.add(new ServletRequestMethodArgumentResolver());
   resolvers.add(new ServletResponseMethodArgumentResolver());
   resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
   resolvers.add(new RedirectAttributesMethodArgumentResolver());
   resolvers.add(new ModelMethodProcessor());
   resolvers.add(new MapMethodProcessor());
   resolvers.add(new ErrorsMethodArgumentResolver());
   resolvers.add(new SessionStatusMethodArgumentResolver());
   resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

   // Custom arguments
   if (getCustomArgumentResolvers() != null) {
      resolvers.addAll(getCustomArgumentResolvers());
   }

   // Catch-all
   resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
   resolvers.add(new ServletModelAttributeMethodProcessor(true));

   return resolvers;
}
默认的returnValueHandles

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

   // Single-purpose return value types
   handlers.add(new ModelAndViewMethodReturnValueHandler());
   handlers.add(new ModelMethodProcessor());
   handlers.add(new ViewMethodReturnValueHandler());
   handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
   handlers.add(new StreamingResponseBodyReturnValueHandler());
   handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
         this.contentNegotiationManager, this.requestResponseBodyAdvice));
   handlers.add(new HttpHeadersReturnValueHandler());
   handlers.add(new CallableMethodReturnValueHandler());
   handlers.add(new DeferredResultMethodReturnValueHandler());
   handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
   handlers.add(new ListenableFutureReturnValueHandler());
   if (completionStagePresent) {
      handlers.add(new CompletionStageReturnValueHandler());
   }

   // Annotation-based return value types
   handlers.add(new ModelAttributeMethodProcessor(false));
   handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
         this.contentNegotiationManager, this.requestResponseBodyAdvice));

   // Multi-purpose return value types
   handlers.add(new ViewNameMethodReturnValueHandler());
   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;
}
基本上我们能用到的都包含了

这里我们就以@RequestBody,@ResponseBody为例进行分析 ,关键类RequestResponseBodyMethodProcessor

@Override
public boolean supportsParameter(MethodParameter parameter) {
   return parameter.hasParameterAnnotation(RequestBody.class);
}

@Override
public boolean supportsReturnType(MethodParameter returnType) {
   return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null ||
         returnType.getMethodAnnotation(ResponseBody.class) != null);
}

该类支持的参数为@RequestBody注解的,支持的返回值为 @ResponseBody注解的

回到前面invokeAndHandle方法中,我们知道请求是由invokeForRequest方法执行,该方法第一行

Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
通过方法名就能知道,是获取请求参数


重点关注resolveArgument


而RequestResponseBodyMethodProcessor 中 resolveArgument的具体实现为:

public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

   Object arg = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
   String name = Conventions.getVariableNameForParameter(parameter);

   WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
   if (arg != null) {
      validateIfApplicable(binder, parameter);
      if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
         throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
      }
   }
   mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());

   return arg;
}
第一行通过 messageConverter读取参数,第二行获取参数名称,第三行绑定参数  本节我们只关心参数的读取  readWithMessageConverters实现为:


@Override
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter methodParam,
      Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

   HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
   ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);

   Object arg = readWithMessageConverters(inputMessage, methodParam, paramType);
   if (arg == null) {
      if (methodParam.getParameterAnnotation(RequestBody.class).required()) {
         throw new HttpMessageNotReadableException("Required request body is missing: " +
               methodParam.getMethod().toGenericString());
      }
   }
   return arg;
}

其中有个判断,如果获取到的参数为空,而Controller方法参数上又添加了@ReqeustBody注解 就会抛异常,具体的readWithMessageConverters方法比较长:



在消息转换器转换消息后,通过binder将内容绑定到对应的方法参数上,整个过程大致就是这样

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值