5

简介

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

HttpMessageConverter虽然功能上也表现为HttpMessage与任意类型的转换,但其接口和Convert SPI并没有继承关系。HttpMessageConverter属于spring-webHttpMessage是SpringMVC对Servlet规范中HttpServletRequestHttpServletResponse的包装,因此接受请求时需要把HttpMessage转换成用户需要的数据,在生成响应时需要把用户生成的数据转换成HttpMessage。如果用户在XML的<mvc:message-converters>中没有指定register-defaults=false,SpringMVC默认至少会注册一些自带的HttpMessageConvertor(从先后顺序排列分别为ByteArrayHttpMessageConverterStringHttpMessageConverterResourceHttpMessageConverterSourceHttpMessageConverterAllEncompassingFormHttpMessageConverter)。

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

两者的分工

Http请求中有几个常用的部分可以用来传递业务信息,以常见的GetPost方法为例。

是否可用 URL Parameter Header Body
Get
Post

那么上述的4个部分都是用HttpMessageConverter来进行类型转换的吗?显然不是,HttpMessageConverterConvert SPI各有分工, HttpMessageConverte只负责解析Http包的Body体部分1,其余部分都交由相关的Convert SPI处理2

是否支持 URL Parameter Header Body
HttpMessageConverter
Convert SPI

除上表所示之外,SpringMVC还有一些需要Convert SPI的场景,如读取Cookie值的@CookieValue(本质是Header),解析矩阵URL的@MatrixVariable(本质是URL),读取本地会话的@SessionAttribute,解析SpEL的@Value

Convert SPI类型转换实例

在SpringMVC中,单次请求的整个处理流程中有哪些地方需要类型转换?以Delete /ajax/shop/12345/blacklist?id=1请求为例,后端对应的处理方法如下。

@DeleteMapping("/ajax/{shopId}/blacklist") @ResponseBody
public boolean deleteBlackItem(@RequestParam Integer id, @PathVariable Integer shopId) {
    //省略
    return true;
} 

由于请求的URL为String类型,而接受的参数idshopId都是Integer类型,因此Spring会自动查找合适的Converter(具体实现为StringToNumberConverterFactory的工厂产品)把字符串“12345”“1”转化为数字123451,分别赋值给shopIdid。处理完业务逻辑后,方法返回true,但需要将其格式化成String类型的“true”才能输出到响应的Body中,这时Spring就会使用StringToBooleanConverter来完成转换。如下图所示,除了上述常见的数据绑定和格式化显示功能,数据验证功能(JSR-303)基于数据绑定也间接利用了这两套SPI。

SpringMVC数据绑定、验证与Convert SPI的关系

结语

在SpringMVC处理请求时,HttpMessageConverterConvert SPI分别用来反序列化请求的Body和非Body部分,即HttpMessageConverter是一套小型、独立、额外为用户提供的专门的Body体的类型转换器;而Convert SPI则与PropertyEditor类似,可以处理更为通用的类型转换。

Reference

  1. SpringMVC数据类型转换——第七章 注解式控制器的数据验证、类型转换及格式化——跟着开涛学SpringMVC

  1. 具体见HandlerMethodInvoker.readWithMessageConverters方法
  2. 具体见不同的HandlerMethodArgumentResolver实现

Jiadong
454 声望42 粉丝

秋名山撒欢,排水沟过弯