当前位置 : 主页 > 编程语言 > java >

RequestResponseBodyMethodProcessor类源码解析

来源:互联网 收集:自由互联 发布时间:2023-03-22
RequestResponseBodyMethodProcessor类源码解析 ​​参数解析器接口实现逻辑​​ ​​返回值处理器接口解析逻辑​​ ​​总结​​ 这个类用于解析@RequestBody入参和@ResponseBody返回值解析问题。

RequestResponseBodyMethodProcessor类源码解析

  • ​​参数解析器接口实现逻辑​​
  • ​​返回值处理器接口解析逻辑​​
  • ​​总结​​

这个类用于解析@RequestBody入参和@ResponseBody返回值解析问题。先查看一些类继承结构图:

RequestResponseBodyMethodProcessor类源码解析_spring

如上图描述,以上几个类作用标记如图。标记几个类的有部分相同的代码逻辑,同时也只有以上几种情况下@ControllerAdvice注解的切面才会生效,其余情况不会的入参和返回值不会对其产生作用。

参数解析器接口实现逻辑

  • HandlerMethodArgumentResolver接口的supportsParameter方法实现逻辑
  • //只支持参数使用@RequestBody注解@Overridepublic boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class);}
  • HandlerMethodArgumentResolver接口的resolveArgument方法实现逻辑
  • @Overridepublic Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { //判断入参是不是Optional类型,是则返回嵌套类型 parameter = parameter.nestedIfOptional(); //读取入参,并使用消息转换器转换参数 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注解或者使用了Vlid开头的注解,则使用Validator接口实现类校验数据(如果适用) validateIfApplicable(binder, parameter); //判断校验结果是否有错误,然后判断当前参数后挨着的是不是BindingResult对象 //如果不是则报错,可以通过全局异常处理的形式处理返回校验结果(推荐) //如果不是,则由ErrorsMethodArgumentResolver参数解析器将校验结果复制到BindingResult入参对象中,可以在方法中处理或者配合切面处理 if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } } if (mavContainer != null) { mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); } } //处理Optional类型入参的情况后返回 return adaptArgumentIfNecessary(arg, parameter);}
  • 使用转换器读取请求参数
  • //读取请求入参@Overrideprotected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { //构建参数 HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); Assert.state(servletRequest != null, "No HttpServletRequest"); ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest); //读取消息 Object arg = readWithMessageConverters(inputMessage, parameter, paramType); //如果入参为空,校验@RequestBodyrequired属性是否为true if (arg == null && checkRequired(parameter)) { throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString()); } return arg;}protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { //获取媒体类型 MediaType contentType; boolean noContentType = false; try { contentType = inputMessage.getHeaders().getContentType(); }catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } if (contentType == null) { noContentType = true; contentType = MediaType.APPLICATION_OCTET_STREAM; } //获取方法类 Class<?> contextClass = parameter.getContainingClass(); //获取入参声明的类型 Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null); if (targetClass == null) { ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter); targetClass = (Class<T>) resolvableType.resolve(); } //获取请求方法(post get...) HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null); Object body = NO_VALUE; EmptyBodyCheckingHttpInputMessage message; try { //消息处理,封装输入流和请求头 message = new EmptyBodyCheckingHttpInputMessage(inputMessage); //循环所有的转换器进行消息转换 for (HttpMessageConverter<?> converter : this.messageConverters) { Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass(); GenericHttpMessageConverter<?> genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null); //判断转换器是否支持读取并在换入参类型 if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) : (targetClass != null && converter.canRead(targetClass, contentType))) { if (logger.isDebugEnabled()) { logger.debug("....."); } //判断请求有请求头体 if (message.hasBody()) { //循环调用ControllerAdvice切面RequestBodyAdvice接口所有实现的beforeBodyRead方法(会先判断是否切当前调用的类) HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType); //调用转换器的read方法,反序列化入参(具体由转换器类实现) body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse)); //循环调用ControllerAdvice切面所有RequestBodyAdvice接口所有实现的afterBodyRead方法(会先判断是否切当前调用的类) body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType); }else { //循环调用ControllerAdvice切面RequestBodyAdvice接口所有实现的handleEmptyBody方法(会先判断是否切当前调用的类) body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType); } break; } } } catch (IOException ex) { throw new HttpMessageNotReadableException("I/O error while reading input message", ex); } if (body == NO_VALUE) { if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) || (noContentType && !message.hasBody())) { return null; } throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes); } return body;}

    使用消息转换器读取消息的时候,是由HttpMessageConverter接口实现的,可以实现该接口自定义转换器。基本上使用内置的转换器就能满足需求了,后续我们介绍一下JSON处理最常用的转换器MappingJackson2HttpMessageConverter类。

  • 获取数据板绑定器
  • //获取数据绑定器 DefaultDataBinderFactory#createBinder方法public final WebDataBinder createBinder( NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception { //创建一个DataBinder实例 WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest); if (this.initializer != null) { //初始化DataBinder实例 this.initializer.initBinder(dataBinder, webRequest); } //先调用@InitBinder注解标记的方法,进行前置复制处理 initBinder(dataBinder, webRequest); return dataBinder;}//初始化DataBinder实例调用ConfigurableWebBindingInitializer#initBinder方法,设置使用的组件,有的是自定义的@Overridepublic void initBinder(WebDataBinder binder) { binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths); if (this.directFieldAccess) { binder.initDirectFieldAccess(); } if (this.messageCodesResolver != null) { binder.setMessageCodesResolver(this.messageCodesResolver); } if (this.bindingErrorProcessor != null) { binder.setBindingErrorProcessor(this.bindingErrorProcessor); } if (this.validator != null && binder.getTarget() != null && this.validator.supports(binder.getTarget().getClass())) { binder.setValidator(this.validator); } if (this.conversionService != null) { binder.setConversionService(this.conversionService); } if (this.propertyEditorRegistrars != null) { for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) { propertyEditorRegistrar.registerCustomEditors(binder); } }}
  • 调用Validator接口实现进行参数校验 @Valid @NotBlank等注解就是在这一步生效的
  • //数据校验 AbstractMessageConverterMethodArgumentResolver#validateIfApplicable方法protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { //获取参数上的所有注解 Annotation[] annotations = parameter.getParameterAnnotations(); for (Annotation ann : annotations) { //获取@Validated注解(或者该注解的子类注解) Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); //获取到的注解不为空或者拿到的注解名是Valid开头则可以校验(@Valid注解生效原因) if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { //获取注解中value属性的值 Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann)); Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); binder.validate(validationHints); break; } }}//调用校验方法DataBinder#validatepublic void validate(Object... validationHints) { for (Validator validator : getValidators()) { //判断校验器的类型,调用校验的方法,将校验结果放到BindingResult对象中 if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) { ((SmartValidator) validator).validate(getTarget(), getBindingResult(), validationHints); }else if (validator != null) { validator.validate(getTarget(), getBindingResult()); } }}

    可以实现Validator接口使用自定义的校验器,但是校验器写一个完备的比较复杂,建议使用默认的校验实现类即可。可以通过实现ConstraintValidator接口扩展自定义的校验规则,自动会添加到默认实现类中。

    返回值处理器接口解析逻辑

  • 支持处理的条件supportsReturnType方法实现逻辑
  • //必须类上面或者方法上有@ResponseBody注解@Overridepublic boolean supportsReturnType(MethodParameter returnType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class));}
  • 处理返回值的逻辑handleReturnValue方法
  • //构建读取组件和参数@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { Object outputValue; Class<?> valueType; Type declaredType; //处理字符数组接口类型,转换成字符串类型 if (value instanceof CharSequence) { outputValue = value.toString(); valueType = String.class; declaredType = String.class; }else { //其余类型 outputValue = value; valueType = getReturnValueType(outputValue, returnType); declaredType = getGenericType(returnType); //获取泛型 } //判断是否是资源类型的返回值(InputStreamResource类或者Resource类) if (isResourceType(value, returnType)) { outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes"); if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null) { Resource resource = (Resource) value; try { List<HttpRange> httpRanges = inputMessage.getHeaders().getRange(); outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value()); outputValue = HttpRange.toResourceRegions(httpRanges, resource); valueType = outputValue.getClass(); declaredType = RESOURCE_REGION_LIST_TYPE; } catch (IllegalArgumentException ex) { outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength()); outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value()); } } } List<MediaType> mediaTypesToUse; //获取媒体类型 MediaType contentType = outputMessage.getHeaders().getContentType(); if (contentType != null && contentType.isConcrete()) { mediaTypesToUse = Collections.singletonList(contentType); } else { HttpServletRequest request = inputMessage.getServletRequest(); List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request); List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType); if (outputValue != null && producibleMediaTypes.isEmpty()) { throw new HttpMessageNotWritableException("...." + valueType); } mediaTypesToUse = new ArrayList<>(); for (MediaType requestedType : requestedMediaTypes) { for (MediaType producibleType : producibleMediaTypes) { if (requestedType.isCompatibleWith(producibleType)) { mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType)); } } } if (mediaTypesToUse.isEmpty()) { if (outputValue != null) { throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes); } return; } MediaType.sortBySpecificityAndQuality(mediaTypesToUse); } MediaType selectedMediaType = null; for (MediaType mediaType : mediaTypesToUse) { if (mediaType.isConcrete()) { selectedMediaType = mediaType; break; } else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break; } } if (selectedMediaType != null) { selectedMediaType = selectedMediaType.removeQualityValue(); //循环所有的转换器进行消息写会响应 for (HttpMessageConverter<?> converter : this.messageConverters) { //判断转换器类型,进行类型转换 GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null); if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(declaredType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { //循环所有ResponseBodyAdvice切面实现类,判断符合处理该返回值则进行调用,按照排序的串行循环调用 outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) converter.getClass(), inputMessage, outputMessage); if (outputValue != null) { //设置响应的Content-Disposition请求头 addContentDispositionHeader(inputMessage, outputMessage); if (genericConverter != null) { //调用转换器的方法将返回值写出响应 genericConverter.write(outputValue, declaredType, selectedMediaType, outputMessage); }else { //调用转换器的方法将返回值写出响应 ((HttpMessageConverter) converter).write(outputValue, selectedMediaType, outputMessage); } if (logger.isDebugEnabled()) { logger.debug("....."); } } return; } } } if (outputValue != null) { throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes); }}

    总结

    这里介绍的流程涉及到了几个扩展接口:

    HttpMessageConverter转换器接口,可以自定义,开发起来比较复杂,内置的基本够用。 Validator 校验器接口,可以实现自定义校验,开发难度大,内置也基本够用

    RequestBodyAdvice接口,在JSON请求入参序列化成对象前后做一些操作,可根据业务逻辑定制 ResponseBodyAdvice接口,在返回值写回给请求方前调用做一些操作,根据业务需要定制

    网友评论