Spring Boot MessageConverter:【从零开始学Spring Boot】-16.Spring Boot MessageConverter消息转
1.自定义MessageConverter执行流程
以 UserController#add1 为例,简单分析一下源码
在 AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters 中有这样一段
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
//...
try {
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
// 遍历所有的 messageConverters
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
GenericHttpMessageConverter<?> genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
// 执行 canRead 方法,判断是否可以支持当前的 Content-Type
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);
// 调用 read 方法解析消息内容
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) 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) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
}
// ...
return body;
}
这里需要遍历 messageConverters 来寻找一个合适的处理器,那么这里的 messageConverters 如何获取到自定义的 HTTPMessageConverter 呢?
其实,在项目启动的时候,自定义 HTTPMessageConverter 被加载到 applicationContext 中。RequestMappingHandlerAdapter 在初始化完成后,调用其 afterPropertiesSet
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();
if (this.argumentResolvers == null) {
// 获取参数处理的 resolvers
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
在 getDefaultArgumentResolvers 中有声明 RequestResponseBodyMethodProcessor 和 RequestPartMethodArgumentResolver,二者都需要调用 getMessageConverters 方法
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// 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()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// 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;
}
它的实现如下
public List<HttpMessageConverter<?>> getMessageConverters() {
return this.messageConverters;
}
这里的 messageConverters 通过构造函数加入了一部分,也在 WebMvcAutoConfiguration 中进行了扩展。
2.自定义MessageConverter加载
在 spring boot 启动的时候,会加载到 WebMvcAutoConfiguration.EnableWebMvcConfiguration 中 requestMappingHandlerAdapter 方法,这个方法用来声明一个 RequestMappingHandlerAdapter 的 bean,它又通过调用 super.requestMappingHandlerAdapter 来进行实例化。
在 super.requestMappingHandlerAdapter 通过adapter.setMessageConverters(getMessageConverters());
将 messageConverters 设置到 adapter 上,这里的 getMessageConverters 实现如下
protected final List<HttpMessageConverter<?>> getMessageConverters() {
if (this.messageConverters == null) {
this.messageConverters = new ArrayList<>();
// 配置 messageConverters
configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
// 如果messageConverters为空,加载默认的配置
addDefaultHttpMessageConverters(this.messageConverters);
}
// 加载扩展的 messageConverter
extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}
在 extendMessageConverters 中通过委派,调用 DelegatingWebMvcConfiguration 的 extendMessageConverters 来扩展 messageConverters,最终调用到 WebMvcConfigurer 的 extendMessageConverters 方法
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.extendMessageConverters(converters);
}
}
而 WebMvcConfig 恰好是 WebMvcConfigurer 的实现类,重写了它的 extendMessageConverters 方法,所以自定义的 HTTPMessageConverter 被加载到 RequestMappingHandlerAdapter 中。