Spring 源码解析十(请求参数注解解析器与响应值注解处理器)

Spring 源码解析十:请求参数注解解析器与响应值注解处理器 在 Spring 源码解析六:处理器映射与处理器适配处理 中,有一些请求参数默认的注解解析器与响应值默认的注解处理器还未解析
请求参数默认的注解解析器主要是:

  • RequestParamMethodArgumentResolver
  • RequestParamMapMethodArgumentResolver
  • PathVariableMethodArgumentResolver
  • PathVariableMapMethodArgumentResolver
  • MatrixVariableMethodArgumentResolver
  • MatrixVariableMapMethodArgumentResolver
  • ServletModelAttributeMethodProcessor
  • RequestResponseBodyMethodProcessor
  • RequestPartMethodArgumentResolver
  • RequestHeaderMethodArgumentResolver
  • RequestHeaderMapMethodArgumentResolver
  • ServletCookieValueMethodArgumentResolver
  • ExpressionValueMethodArgumentResolver
  • SessionAttributeMethodArgumentResolver
  • RequestAttributeMethodArgumentResolver
  • ServletRequestMethodArgumentResolver
  • ServletResponseMethodArgumentResolver
  • HttpEntityMethodProcessor
  • RedirectAttributesMethodArgumentResolver
  • ModelMethodProcessor
  • MapMethodProcessor
  • ErrorsMethodArgumentResolver
  • SessionStatusMethodArgumentResolver
  • UriComponentsBuilderMethodArgumentResolver
  • PrincipalMethodArgumentResolver
响应值默认的注解处理器主要是:
  • ModelAndViewMethodReturnValueHandler
  • ModelMethodProcessor
  • ViewMethodReturnValueHandler
  • ResponseBodyEmitterReturnValueHandler
  • StreamingResponseBodyReturnValueHandler
  • HttpEntityMethodProcessor
  • HttpHeadersReturnValueHandler
  • CallableMethodReturnValueHandler
  • DeferredResultMethodReturnValueHandler
  • AsyncTaskMethodReturnValueHandler
  • ServletModelAttributeMethodProcessor
  • RequestResponseBodyMethodProcessor
  • ViewNameMethodReturnValueHandler
  • MapMethodProcessor
  • ModelAndViewResolverMethodReturnValueHandler
下面我们选一些典型的来解析
1. RequestParamMethodArgumentResolver RequestParamMethodArgumentResolver
的主要功能是解析 @RequestParam
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver implements UriComponentsContributor {}

先来看看 AbstractNamedValueMethodArgumentResolver
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver { // 解析参数 @Override public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { // 获取名称值信息 NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); // 如果名字里有表达式,解析表达式 Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name); // 解析名称对应的值,由子类实现 Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest); // 如果没有值 if (arg == null) { // 有defaultValue的话,解析defaultValue的表达式,并使用默认值 if (namedValueInfo.defaultValue != null) { arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue); }// ... 代码省略 }// ... 代码省略if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); try { // 转换值String类型到目标类型 arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter); } catch (ConversionNotSupportedException ex) { // ... 代码省略 }// ... 代码省略 }// 后置处理,由子类实现 handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg; } }

再来看看 RequestParamMethodArgumentResolver
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver implements UriComponentsContributor { // 解析名字 @Override protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { // 获取原生的HttpServletRequest HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); // ... 代码省略Object arg = null; MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class); // 文件上传处理 if (multipartRequest != null) { List files = multipartRequest.getFiles(name); if (!files.isEmpty()) { arg = (files.size() == 1 ? files.get(0) : files); } } // 获取参数值 if (arg == null) { String[] paramValues = request.getParameterValues(name); if (paramValues != null) { arg = (paramValues.length == 1 ? paramValues[0] : paramValues); } } return arg; }}

2. RequestParamMapMethodArgumentResolver RequestParamMapMethodArgumentResolver
的主要功能是解析 @RequestParam,但不指定参数名字,返回整个参数 Map
public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver { // 解析参数 @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { // MultiValueMap if (MultiValueMap.class.isAssignableFrom(parameter.getParameterType())) { Class valueType = resolvableType.as(MultiValueMap.class).getGeneric(1).resolve(); // 文件上传 if (valueType == MultipartFile.class) { // ... 代码省略 } // 单片文件上传 else if (valueType == Part.class) { // ... 代码省略 } // 普通字符 else { Map parameterMap = webRequest.getParameterMap(); MultiValueMap result = new LinkedMultiValueMap<>(parameterMap.size()); parameterMap.forEach((key, values) -> { for (String value : values) { result.add(key, value); } }); return result; } } // 普通Map else { Class valueType = resolvableType.asMap().getGeneric(1).resolve(); // 文件上传 if (valueType == MultipartFile.class) { // ... 代码省略 } // 单片文件上传 else if (valueType == Part.class) { // ... 代码省略 } // 普通字符 else { Map parameterMap = webRequest.getParameterMap(); Map result = CollectionUtils.newLinkedHashMap(parameterMap.size()); parameterMap.forEach((key, values) -> { if (values.length > 0) { result.put(key, values[0]); } }); return result; } } } }

3. PathVariableMethodArgumentResolver PathVariableMethodArgumentResolver
的主要功能是解析 @PathVariable
public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver implements UriComponentsContributor { // 解析名字 @Override protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { // 获取解析好的Map Map uriTemplateVars = (Map) request.getAttribute( HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); // 从Map中取 return (uriTemplateVars != null ? uriTemplateVars.get(name) : null); } }

4. RequestResponseBodyMethodProcessor RequestResponseBodyMethodProcessor
的主要功能是处理 @RequestBody@ResponseBody
先来看看继承关系
- AbstractMessageConverterMethodArgumentResolver - AbstractMessageConverterMethodProcessor - RequestResponseBodyMethodProcessor

4.1. AbstractMessageConverterMethodArgumentResolver
AbstractMessageConverterMethodArgumentResolver
的主要功能是可以使用消息转换器把输入转换成需要的对象
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver { // 使用消息转换器把请求体读取为对象 protected Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { // ... 代码省略// 获取转换到目标对象的类 Class targetClass = (targetType instanceof Class ? (Class) targetType : null); if (targetClass == null) { ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter); targetClass = (Class) resolvableType.resolve(); }// ... 代码省略Object body = NO_VALUE; EmptyBodyCheckingHttpInputMessage message; try { // 初始化一个输入流读取器 message = new EmptyBodyCheckingHttpInputMessage(inputMessage); // 遍历转换器 for (HttpMessageConverter converter : this.messageConverters) { // 转换类型 Class> converterType = (Class>) converter.getClass(); // 是否是GenericHttpMessageConverter GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter) converter : null); // 读取请求体,处理 if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) : (targetClass != null && converter.canRead(targetClass, contentType))) { if (message.hasBody()) { // 读取前处理 HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType); // 读取请求体 body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : ((HttpMessageConverter) converter).read(targetClass, msgToUse)); // 读取后处理 body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType); } else { // 空请求体 body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType); } break; } } } catch (IOException ex) { // ... 代码省略 }// ... 代码省略return body; } }

4.2. AbstractMessageConverterMethodProcessor
AbstractMessageConverterMethodProcessor
的主要功能是可以使用消息转换器把响应对象转换成输出
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver implements HandlerMethodReturnValueHandler { // 转换对象为输出 protected void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { // 响应体 Object body; // 值类型 Class valueType; // 目标类型 Type targetType; // 字符 if (value instanceof CharSequence) { body = value.toString(); valueType = String.class; targetType = String.class; } // 非字符 else { body = value; valueType = getReturnValueType(body, returnType); targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass()); }// 如果是输出为资源类型,二进制流或文件 if (isResourceType(value, returnType)) { outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes"); if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null && outputMessage.getServletResponse().getStatus() == 200) { Resource resource = (Resource) value; try { List httpRanges = inputMessage.getHeaders().getRange(); outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value()); body = HttpRange.toResourceRegions(httpRanges, resource); valueType = body.getClass(); targetType = RESOURCE_REGION_LIST_TYPE; } catch (IllegalArgumentException ex) { // ... 代码省略 } } }MediaType selectedMediaType = null; // 输出内容类型content-type MediaType contentType = outputMessage.getHeaders().getContentType(); // 有内容类型 boolean isContentTypePreset = contentType != null && contentType.isConcrete(); if (isContentTypePreset) { selectedMediaType = contentType; } else { // ... 代码省略,如果没有内容类型,就从内容判断 }// 遍历消息转换器 for (HttpMessageConverter converter : this.messageConverters) { // 是否是GenericHttpMessageConverter GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter) converter : null); if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { // 输出前置处理 body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, (Class>) converter.getClass(), inputMessage, outputMessage); if (body != null) { // 添加Content-Disposition头 addContentDispositionHeader(inputMessage, outputMessage); // 把body转换并输出到outputMessage if (genericConverter != null) { genericConverter.write(body, targetType, selectedMediaType, outputMessage); } else { ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage); } } return; } }// ... 代码省略 } }

4.3. RequestResponseBodyMethodProcessor
RequestResponseBodyMethodProcessor
的主要功能是输入与输出都可以使用消息转换器转换
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { // 解析参数 @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { // 使用消息转换器把请求体读取为对象 Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()); // 变量名 String name = Conventions.getVariableNameForParameter(parameter); // 有数据绑定工厂 if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); if (arg != null) { // 如果有@Validated的注解,则需要验证 validateIfApplicable(binder, parameter); // ... 代码省略 }// ... 代码省略 }// 适配一下Optional return adaptArgumentIfNecessary(arg, parameter); }// 使用消息转换器把请求体读取为对象 @Override protected Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { // 获取原始的请求对象 HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest); // 使用父类的方法转换 Object arg = readWithMessageConverters(inputMessage, parameter, paramType); // ... 代码省略return arg; } }

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { // 处理响应值 @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // 使用父类的方法转换对象为输出 writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); } }

5. HttpEntityMethodProcessor HttpEntityMethodProcessor
的主要功能是处理 HttpEntity
public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor { // 解析名字 @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws IOException, HttpMediaTypeNotSupportedException {// 创建ServletServerHttpRequest ServletServerHttpRequest inputMessage = createInputMessage(webRequest); // 获取数据类型 Type paramType = getHttpEntityType(parameter); // 使用消息转换器把请求体读取为对象 Object body = readWithMessageConverters(webRequest, parameter, paramType); // 如果RequestEntity类型,封装为RequestEntity,不然就是普通的HttpEntity if (RequestEntity.class == parameter.getParameterType()) { return new RequestEntity<>(body, inputMessage.getHeaders(), inputMessage.getMethod(), inputMessage.getURI()); } else { return new HttpEntity<>(body, inputMessage.getHeaders()); } } }

public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor { // 处理响应值 @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // ... 代码省略// 创建输入输出消息对象 ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); HttpEntity responseEntity = (HttpEntity) returnValue; // 获取输出消息头 HttpHeaders outputHeaders = outputMessage.getHeaders(); HttpHeaders entityHeaders = responseEntity.getHeaders(); // ... 代码省略,把entityHeaders载入outputHeadersif (responseEntity instanceof ResponseEntity) { // ... 代码省略,如果是 get/head 方法,并且是200状态码,直接输入 }// 使用父类的方法转换对象为输出 writeWithMessageConverters(responseEntity.getBody(), returnType, inputMessage, outputMessage); // ... 代码省略 } }

6. ModelAndViewMethodReturnValueHandler ModelAndViewMethodReturnValueHandler
的主要功能是输出 ModelAndView
public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturnValueHandler { // 处理响应值 @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 没有响应值,直接返回 if (returnValue =https://www.it610.com/article/= null) { mavContainer.setRequestHandled(true); return; }ModelAndView mav = (ModelAndView) returnValue; // 是viewName if (mav.isReference()) { String viewName = mav.getViewName(); mavContainer.setViewName(viewName); if (viewName != null && isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } // 是view对象 else { View view = mav.getView(); mavContainer.setView(view); if (view instanceof SmartView && ((SmartView) view).isRedirectView()) { mavContainer.setRedirectModelScenario(true); } } mavContainer.setStatus(mav.getStatus()); mavContainer.addAllAttributes(mav.getModel()); } }

7. StreamingResponseBodyReturnValueHandler StreamingResponseBodyReturnValueHandler
的主要功能是输出 StreamingResponseBody
public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler { // 处理响应值 @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 没有响应值,直接返回 if (returnValue =https://www.it610.com/article/= null) { mavContainer.setRequestHandled(true); return; }// 获取原始输出 HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); ServerHttpResponse outputMessage = new ServletServerHttpResponse(response); // 如果是ResponseEntity,并且有响应体,直接输出 if (returnValue instanceof ResponseEntity) { ResponseEntity responseEntity = (ResponseEntity) returnValue; response.setStatus(responseEntity.getStatusCodeValue()); outputMessage.getHeaders().putAll(responseEntity.getHeaders()); returnValue = https://www.it610.com/article/responseEntity.getBody(); if (returnValue == null) { mavContainer.setRequestHandled(true); outputMessage.flush(); return; } }StreamingResponseBody streamingBody = (StreamingResponseBody) returnValue; Callable callable = new StreamingResponseBodyTask(outputMessage.getBody(), streamingBody); // 异步输出 WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer); } }

8. ViewNameMethodReturnValueHandler ViewNameMethodReturnValueHandler
的主要功能是输出视图名字
public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler { // 处理响应值 @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {if (returnValue instanceof CharSequence) { String viewName = returnValue.toString(); mavContainer.setViewName(viewName); if (isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } else if (returnValue != null) { // should not happen throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); } } }

后续 更多博客,查看 https://github.com/senntyou/blogs
作者:深予之 (@senntyou)
【Spring 源码解析十(请求参数注解解析器与响应值注解处理器)】版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)

    推荐阅读