HttpMessageConverter和Converter的区别

参考:【SpringMVC】浅谈Convert/Format机制与HttpMessageConverter的关系

HttpMessageConverter和Converter的区别

Spring3 引入了Convert/Format SPIConvert SPI可以实现任意java类型的转换;Format SPI支持国际化,并在前者的基础上实现了 String 与任意类型的转换。这两类 SPI 属于spring-core,被整个spring-framework共享,是一种通用的类型转换器。

HttpMessageConverter和Converter的区别_第1张图片

HttpMessageConverter 属于spring-web,HttpMessageConverter是将HTTP请求内容转换成java对象,以及将java对象转换成HTTP响应内容,说白了就是对HTTP的反序列化和序列化,它的仅仅被用于HTTP主体和java对象之间的转换。

SpringMVC 默认会注册一些自带的HttpMessageConvertor(从先后顺序排列分别为ByteArrayHttpMessageConverterStringHttpMessageConverterResourceHttpMessageConverterSourceHttpMessageConverterAllEncompassingFormHttpMessageConverter)。

如果后端服务使用Restful API的形式,一般使用 JSON 作为前后端通信的格式规范,由于 SpringMVC 自带MappingJackson2HttpMessageConverter,在依赖中引入 jackson 包后,容器会把MappingJackson2HttpMessageConverter自动注册到 converter 链的末尾。

源码分析

HandlerAdapter执行目标方法之前,需要调用resolveArgument() 依次解析出每个入参对象,然后才会执行目标方法。

resolveArgument()内部,首先调用getArgumentResolver() 获得能解析当前入参的HandlerMethodArgumentResolver解析器,然后调用这个解析器的resolveArgument() 获得一个入参对象。

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

//根据参数类型和参数上的注解, 获得能解析这个参数的解析器
  HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
  if (resolver == null) {
    throw new IllegalArgumentException("Unsupported parameter type [" +
        parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
  }
  //解析获得入参对象
  return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

getArgumentResolver() 会返回什么类型的HandlerMethodArgumentResolver,这与入参类型入参上的注解有关,Spring MVC默认注册了以下方法参数解析器:

HttpMessageConverter和Converter的区别_第2张图片

都是字如其意的名称,比如PathVariableMethodArgumentResolver用于解析 @PathVariable 标注的入参,RequestParamMethodArgumentResolver用于解析 @RequestParam 标注的入参等。

关键的是:

有一些解析器是调用**binder.convertIfNecessary(),使用绑定器的ConversionService内部适当的Converter进行类型转换,通常是字符串转入参对象(因为是超文本协议嘛),比如PathVariableMethodArgumentResolverRequestParamMethodArgumentResolver**等。

有一些解析器是调用**readWithMessageConverters(),使用适当的HttpMessageConverter将HTTP请求转换为入参对象,比如RequestResponseBodyMethodProcessorHttpEntityMethodProcessor**等。


下面列举两个解析器的resolveArgument() 源码看看:

RequestParamMethodArgumentResolverresolveArgument() 方法:

首先获取@RequestParam注解指定的请求参数的值,然后交给数据绑定器内部的ConversionService转换成入参对象。

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

  NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
  MethodParameter nestedParameter = parameter.nestedIfOptional();
  
  //获取@RequestParam注解指定的请求参数名称
  Object resolvedName = resolveStringValue(namedValueInfo.name);
  if (resolvedName == null) {
    throw new IllegalArgumentException(
        "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
  }
  
  //获取请求参数值
  Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
  if (arg == null) {
    if (namedValueInfo.defaultValue != null) {
      arg = resolveStringValue(namedValueInfo.defaultValue);
    }
    else if (namedValueInfo.required && !nestedParameter.isOptional()) {
      handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
    }
    arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
  }
  else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
    arg = resolveStringValue(namedValueInfo.defaultValue);
  }

  if (binderFactory != null) {
    //创建数据绑定器
    WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
    try {
    //使用绑定器内部的ConversionService将这个请求参数转换成入参对象
      arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
    }
    catch (ConversionNotSupportedException ex) {
      throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
          namedValueInfo.name, parameter, ex.getCause());
    }
    catch (TypeMismatchException ex) {
      throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
          namedValueInfo.name, parameter, ex.getCause());
    }
  }

  handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
  
  //返回入参对象
  return arg;
}

RequestResponseBodyMethodProcessorresolveArgument() 方法:

首先调用readWithMessageConverters() ,选取适当的HTTPMessageConverter将HTTP请求内容转换成入参对象,最后使用校验器校验,然后返回入参。

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

  parameter = parameter.nestedIfOptional();
  //选取合适的HTTPMessageConverter将请求内容转换成入参对象
  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) {
      //如果入参标了@Valid或@Validated的话, 使用校验器进行校验
      validateIfApplicable(binder, parameter);
      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());
    }
  }
  //返回入参对象
  return adaptArgumentIfNecessary(arg, parameter);
}

你可能感兴趣的:(Spring,MVC,JavaEE)