HttpMessageConverters类
HttpMessageConverters是org.springframework.boot.autoconfigure.http下的一个类,是
Spring Boot提供的管理应用程序中使用HttpMessageConverter的Bean。
提供一种方便的方法来添加和配置额外的HttpMessageConverter到 Web 应用程序。如果需要,可以使用特定的HttpMessageConverters注册此 bean 的实例,否则将使用默认转换器。
HttpMessageConverters维护了一个HttpMessageConverter集合。
private final List<HttpMessageConverter<?>> converters;
注入HttpMessageConverters
在HttpMessageConvertersAutoConfiguration类中,注入了一个默认的HttpMessageConverters。
@Bean
@ConditionalOnMissingBean
public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
return new HttpMessageConverters((Collection)converters.orderedStream().collect(Collectors.toList()));
}
调用了HttpMessageConverters的构造方法。
public HttpMessageConverters(boolean addDefaultConverters, Collection<HttpMessageConverter<?>> converters) {
List<HttpMessageConverter<?>> combined = this.getCombinedConverters(converters, addDefaultConverters ? this.getDefaultConverters() : Collections.emptyList());
combined = this.postProcessConverters(combined);
this.converters = Collections.unmodifiableList(combined);
}
HttpMessageConverters构造方法最终调用到WebMvcConfigurationSupport的addDefaultHttpMessageConverters添加转换器。
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
// 1. 添加ByteArrayHttpMessageConverter、StringHttpMessageConverter、ResourceHttpMessageConverter、ResourceRegionHttpMessageConverter
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
// 2. 没有忽略XML,添加SourceHttpMessageConverter。
if (!shouldIgnoreXml) {
try {
messageConverters.add(new SourceHttpMessageConverter());
} catch (Throwable var3) {
}
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
// 3. 是否存在com.rometools.rome.feed.WireFeed这个类,有则添加AtomFeedHttpMessageConverter、RssChannelHttpMessageConverter
if (romePresent) {
messageConverters.add(new AtomFeedHttpMessageConverter());
messageConverters.add(new RssChannelHttpMessageConverter());
}
// 4. 没有配置忽略XML
Jackson2ObjectMapperBuilder builder;
if (!shouldIgnoreXml) {
if (jackson2XmlPresent) {
builder = Jackson2ObjectMapperBuilder.xml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
// 5. 存在com.fasterxml.jackson.dataformat.xml.XmlMapper这个类,添加MappingJackson2XmlHttpMessageConverter解析器。
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
} else if (jaxb2Present) {
// 6. 存在javax.xml.bind.Binder类,添加Jaxb2RootElementHttpMessageConverter
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
}
// 7. 存在kotlinx.serialization.json.Json,添加KotlinSerializationJsonHttpMessageConverter
if (kotlinSerializationJsonPresent) {
messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
}
// 8. 存在javax.xml.bind.Binder类,添加Jaxb2RootElementHttpMessageConverter
if (jackson2Present) {
builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
}
// ......others
}
可以看到在addDefaultHttpMessageConverters方法中,会去classLoader中查询相关的类,有最添加相关的解析器,比如我们引入了om.google.gson.Gson包,就会添加GsonHttpMessageConverter转换器。
可以看到默认加载了10个转换器。
报文转换源码分析
HttpMessageConverter执行报文转换的基本流程如下。
接下来使用下面这个使用了@ResponseBody、@RequestBody注解的控制器方法,是如何进行报文转换的。
@PostMapping("/testRequestBody")
@ResponseBody
public Object testRequestBody(@RequestBody User user) {
return user;
}
1. 初始化处理器适配器
在之前的文档中,分析了HttpMessageConverters的初始化,了解到了有哪些HttpMessageConverter注入了IOC容器中的。
在DispatcherServlet流程分析中,我们没分析到HttpMessageConverter是如何转换的,实际是因为HttpMessageConverter不直接参与DispatcherServlet的执行流程,而是由处理器适配器HandlerAdapter来调用执行的。
在WebMvcConfigurationSupport类中,我们可以看到注入RequestMappingHandlerAdapter适配器时,加载了很多HttpMessageConverter,上面HttpMessageConverters加载也是调用的此方法。
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = this.createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(contentNegotiationManager);
adapter.setMessageConverters(this.getMessageConverters());
}
最终,适配器,获取到了这些Converters,关于适配器组件的相关分析,后续会补上。
2. 转换请求报文
发送请求,会进入到DispatcherServlet的doDispatch方法,适配器进行执行处理,调用的是doDispatch的如下代码:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
handle方法,调用的是RequestMappingHandlerAdapter父类AbstractHandlerMethodAdapter的handle方法。
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return this.handleInternal(request, response, (HandlerMethod)handler);
}
接下来调转到RequestMappingHandlerAdapter的handleInternal方法。
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 1. 检查请求
this.checkRequest(request);
ModelAndView mav;
// 2. 设置了Session同步,则会加锁执行
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
// 3. 调用处理程序方法
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
return mav;
}
handleInternal接着进入到invokeHandlerMethod,开始执行处理器方法,invokeHandlerMethod会设置一些解析器、处理器。
invokeHandlerMethod方法会进入invokeAndHandle调用和处理请求。其中调用的invokeForRequest就是处理请求了。
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
invokeForRequest方法会首先获取控制器参数值getMethodArgumentValues。
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return this.doInvoke(args);
}
InvocableHandlerMethod.getMethodArgumentValues方法如下:
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 1. 获取方法的参数对象
MethodParameter[] parameters = this.getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
Object[] args = new Object[parameters.length];
// 2. 循环参数
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
// 3. 根据参数获取参数解析器
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 4. 调用解析器解析参数
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
// .... others
}
resolveArgument方法,最终调用到RequestResponseBodyMethodProcessor。它就是ResponseBody、RequestBody注解标识方法的参数解析器。
RequestResponseBodyMethodProcessor的resolveArgument源码如下:
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
// 1. 消息转换
Object arg = this.readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
// 2. 获取参数名
String name = Conventions.getVariableNameForParameter(parameter);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
// .... others
}
在resolveArgument方法中,终于看到了HttpMessageConverter了,其readWithMessageConverters方法如下:
接着调用的父类readWithMessageConverters方法,读取请求消息,转换为Java对象
@Nullable
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
boolean noContentType = false;
MediaType contentType;
try {
// 1. 获取contentType application/json;charset=UTF-8
contentType = inputMessage.getHeaders().getContentType();
} catch (InvalidMediaTypeException var16) {
throw new HttpMediaTypeNotSupportedException(var16.getMessage());
}
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
// 2. 获取class org.pearl.springboot.minio.controller.MvcController
Class<?> contextClass = parameter.getContainingClass();
// 3. 获取参数class class org.pearl.springboot.minio.pojo.query.User
Class<T> targetClass = targetType instanceof Class ? (Class)targetType : null;
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = resolvableType.resolve();
}
HttpMethod httpMethod = inputMessage instanceof HttpRequest ? ((HttpRequest)inputMessage).getMethod() : null;
Object body = NO_VALUE;
AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage message;
try {
label98: {
// 4. 获取到请求报文、请求头
message = new AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage(inputMessage);
// 5. 获取到消息转换器集合
Iterator var11 = this.messageConverters.iterator();
HttpMessageConverter converter;
Class converterType;
GenericHttpMessageConverter genericConverter;
// 循环
while(true) {
if (!var11.hasNext()) {
break label98;
}
// 消息转换器
converter = (HttpMessageConverter)var11.next();
// 消息转换器 Class名
converterType = converter.getClass();
// 6. 是不是通用 Http 消息转换器GenericHttpMessageConverter
genericConverter = converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter)converter : null;
if (genericConverter != null) {
if (genericConverter.canRead(targetType, contextClass, contentType)) {
break;
}
} else if (targetClass != null && converter.canRead(targetClass, contentType)) {
break;
}
}
// 7. 处理请求报文
if (message.hasBody()) {
HttpInputMessage msgToUse = this.getAdvice().beforeBodyRead(message, parameter, targetType, converterType); // 8. 调用消息转换器MappingJackson2HttpMessageConverter, 转换数据为Java对象
body = genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : converter.read(targetClass, msgToUse);
body = this.getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
} else {
body = this.getAdvice().handleEmptyBody((Object)null, message, parameter, targetType, converterType);
}
}
// .... others
}
可以看到解析参数时,这里使用的是MappingJackson2HttpMessageConverter转换器,使用 objectMapper.readValue方法,将请求报文转为JAVA对象,这个读取请求报文,转为JAVA对象的流程就结束了。
3. 转换响应报文
在InvocableHandlerMethod.invokeForRequest方法处理完参数之后,就开始执行执行器方法了,也就是我们写的controller方法。
controller方法执行完成之后,重新回到ServletInvocableHandlerMethod.invokeAndHandle方法,并获取到了方法返回值。
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
// .... others
mavContainer.setRequestHandled(false);
try {
// 1. 处理响应值
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
}
}
handleReturnValue方法会进入到HandlerMethodReturnValueHandlerComposite类中,会调用处理器RequestResponseBodyMethodProcessor。
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
} else {
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
handler.handleReturnValue会根据返回值,创建ServletServerHttpResponse对象,
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
最懂调用writeWithMessageConverters,也是匹配一个转换器将返回值对象写入到响应体中,然后经过DispathServlet的其他处理,浏览器就收到响应的JAVA对象了。
版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: