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

来源:互联网 发布:java中绝对值函数 编辑:程序博客网 时间:2024/05/17 05:50


         前一篇博客中,我们分析了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

@Overridepublic boolean supportsParameter(MethodParameter parameter) {   return parameter.hasParameterAnnotation(RequestBody.class);}@Overridepublic 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实现为:


@Overrideprotected <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 0