1. HttpMessageConverter的加载

  • 首先我们找到WebMvcAutoConfiguration这个类

    在其中我们可以看到这么一段代码

    @Configuration
    @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
    @Order(0) //表示最先加载
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware {
    private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
    private final ResourceProperties resourceProperties;
    private final WebMvcProperties mvcProperties;
    private final ListableBeanFactory beanFactory;
    private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;
    final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
    private ResourceLoader resourceLoader; public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {
    this.resourceProperties = resourceProperties;
    this.mvcProperties = mvcProperties;
    this.beanFactory = beanFactory;
    this.messageConvertersProvider = messageConvertersProvider;
    this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
    } public void setResourceLoader(ResourceLoader resourceLoader) {
    this.resourceLoader = resourceLoader;
    } public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { this.messageConvertersProvider.ifAvailable((customConverters) -> {
    // 添加自定义的converter
    converters.addAll(customConverters.getConverters());
    });
    }
    // 省略一部分不重要的代码
    .....
  • 上面我们要分析的核心代码就是configureMessageConverters(List<HttpMessageConverter<?>> converters)这个方法,首先我要知道这个方法的入参是什么,在哪里初始化的。

  • 我们可以看到在这个类上有一个@import注解

    @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})

  • 我们可以跟一下这个类----》EnableWebMvcConfiguration

  • 我们可以发现这个类继承了WebMvcConfigurationSupport,核心的关于messageConverter的代码如下:

    protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
    StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
    stringHttpMessageConverter.setWriteAcceptCharset(false);
    messageConverters.add(new ByteArrayHttpMessageConverter());
    messageConverters.add(stringHttpMessageConverter);
    messageConverters.add(new ResourceHttpMessageConverter());
    messageConverters.add(new ResourceRegionHttpMessageConverter()); try {
    messageConverters.add(new SourceHttpMessageConverter());
    } catch (Throwable var4) {
    } messageConverters.add(new AllEncompassingFormHttpMessageConverter());
    if (romePresent) {
    messageConverters.add(new AtomFeedHttpMessageConverter());
    messageConverters.add(new RssChannelHttpMessageConverter());
    } Jackson2ObjectMapperBuilder builder;
    if (jackson2XmlPresent) {
    builder = Jackson2ObjectMapperBuilder.xml();
    if (this.applicationContext != null) {
    builder.applicationContext(this.applicationContext);
    } messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
    } else if (jaxb2Present) {
    messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
    } if (jackson2Present) {
    builder = Jackson2ObjectMapperBuilder.json();
    if (this.applicationContext != null) {
    builder.applicationContext(this.applicationContext);
    } messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    } else if (gsonPresent) {
    messageConverters.add(new GsonHttpMessageConverter());
    } else if (jsonbPresent) {
    messageConverters.add(new JsonbHttpMessageConverter());
    } if (jackson2SmilePresent) {
    builder = Jackson2ObjectMapperBuilder.smile();
    if (this.applicationContext != null) {
    builder.applicationContext(this.applicationContext);
    } messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
    } if (jackson2CborPresent) {
    builder = Jackson2ObjectMapperBuilder.cbor();
    if (this.applicationContext != null) {
    builder.applicationContext(this.applicationContext);
    } messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
    } }
  • 从这段代码中我们可以知道

    1. spring中默认添加了几个消息转换器,比如ByteArrayHttpMessageConverter,stringHttpMessageConverter,ResourceHttpMessageConverter等等
    2. 会根据Jackson,Gson等添加对应的小心转换器

2. 从StringMessageConverter探究消息转换器的原理

public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {
// 默认字符集
public static final Charset DEFAULT_CHARSET;
@Nullable
private volatile List<Charset> availableCharsets;
private boolean writeAcceptCharset; public StringHttpMessageConverter() {
this(DEFAULT_CHARSET);
} public StringHttpMessageConverter(Charset defaultCharset) {
super(defaultCharset, new MediaType[]{MediaType.TEXT_PLAIN, MediaType.ALL});
this.writeAcceptCharset = true;
} public void setWriteAcceptCharset(boolean writeAcceptCharset) {
this.writeAcceptCharset = writeAcceptCharset;
} public boolean supports(Class<?> clazz) {
return String.class == clazz;
} protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
Charset charset = this.getContentTypeCharset(inputMessage.getHeaders().getContentType());
return StreamUtils.copyToString(inputMessage.getBody(), charset);
} protected Long getContentLength(String str, @Nullable MediaType contentType) {
Charset charset = this.getContentTypeCharset(contentType);
return (long)str.getBytes(charset).length;
} protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
if (this.writeAcceptCharset) {
outputMessage.getHeaders().setAcceptCharset(this.getAcceptedCharsets());
} Charset charset = this.getContentTypeCharset(outputMessage.getHeaders().getContentType());
StreamUtils.copy(str, charset, outputMessage.getBody());
} protected List<Charset> getAcceptedCharsets() {
List<Charset> charsets = this.availableCharsets;
if (charsets == null) {
charsets = new ArrayList(Charset.availableCharsets().values());
this.availableCharsets = (List)charsets;
} return (List)charsets;
} private Charset getContentTypeCharset(@Nullable MediaType contentType) {
if (contentType != null && contentType.getCharset() != null) {
return contentType.getCharset();
} else if (contentType != null && contentType.isCompatibleWith(MediaType.APPLICATION_JSON)) {
return StandardCharsets.UTF_8;
} else {
Charset charset = this.getDefaultCharset();
Assert.state(charset != null, "No default charset");
return charset;
}
} static {
// 默认字符集为ISO-8859-1
DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
}
}

​ 上面代码的核心就在两个读写的方法上,分别是将字符串转换为httpMessage,跟将httpMessage转换为字符串

// 读方法
protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
Charset charset =
// 根据请求头中的信息,得到编码类型并转换
this.getContentTypeCharset(inputMessage.getHeaders().getContentType());
return StreamUtils.copyToString(inputMessage.getBody(), charset);
}
// 写方法
protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
if (this.writeAcceptCharset) {
outputMessage.getHeaders().setAcceptCharset(this.getAcceptedCharsets());
} Charset charset =
// 根据响应头中的编码类型,将字符串转换为httpMessage消息
this.getContentTypeCharset(outputMessage.getHeaders().getContentType());
StreamUtils.copy(str, charset, outputMessage.getBody());
}

spring学习笔记(七)HttpMessageConverter的更多相关文章

  1. Spring学习笔记(七)模拟实际开发过程的调用过程XML版-Setter方式注入

    模拟实际开发过程的调用过程XML版-Setter方式注入 源码获取github [TOC] 1.项目结构 2.jar包跟上个一样 3.重写set方法 UserServiceImpl.java 1234 ...

  2. 【Spring学习笔记-MVC-3】SpringMVC返回Json数据-方式1

    <Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...

  3. 1.《Spring学习笔记-MVC》系列文章,讲解返回json数据的文章共有3篇,分别为:

    转自:https://www.cnblogs.com/ssslinppp/p/4528892.html [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://w ...

  4. 【Spring学习笔记-MVC-3.1】SpringMVC返回Json数据-方式1-扩展

    <Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...

  5. (转)Qt Model/View 学习笔记 (七)——Delegate类

    Qt Model/View 学习笔记 (七) Delegate  类 概念 与MVC模式不同,model/view结构没有用于与用户交互的完全独立的组件.一般来讲, view负责把数据展示 给用户,也 ...

  6. spring学习笔记(一) Spring概述

    博主Spring学习笔记整理大部分内容来自Spring实战(第四版)这本书.  强烈建议新手购入或者需要电子书的留言. 在学习Spring之前,我们要了解这么几个问题:什么是Spring?Spring ...

  7. Learning ROS for Robotics Programming Second Edition学习笔记(七) indigo PCL xtion pro live

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS forRobotics Pro ...

  8. Java框架spring 学习笔记(十八):事务管理(xml配置文件管理)

    在Java框架spring 学习笔记(十八):事务操作中,有一个问题: package cn.service; import cn.dao.OrderDao; public class OrderSe ...

  9. Typescript 学习笔记七:泛型

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

随机推荐

  1. 2019-05-19 Python之第一个爬虫和测试

    一.使用request和get访问某个网页20次并且打印返回状态,内容   扩展:常见状态码含义 200 - 服务器成功返回网页,404 - 请求的网页不存在,403(禁止)服务器拒绝请求,404(未 ...

  2. 数据结构(C语言版)---线性表链式存储表示

    1.单链表:线性表的链式存储. 1)特点:用一组任意的存储单元存储数据元素(存储单元可以连续,也可以不连续),逻辑上相邻的元素存储位置不一定相邻. 2)结点包括两个域:数据域(存储数据元素信息).指针 ...

  3. E - Dividing Chocolate ATcoder

    题目大意:切割图形,给你一个非0即1的矩阵,将它切割成多个长方形,使每个小长方形中1的个数不得多于k个,切割的规则,要么切一整行,要么是一整列. 题解: 二进制枚举. 注意行数最大才是10.用二进制枚 ...

  4. nginx配置虚拟主机、反向代理和负载均衡

    为了实现这个功能,需要修改nginx的配置文件,将nginx.conf清理一下,使结构更清晰. worker_processes ; events { worker_connections ; } h ...

  5. JS 的基础概念

    本篇文章主要讲述js的基础知识! 首先,我们要明白什么是JS,JS就是 javascript 的简称,是一种轻量级,弱类型的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能, ...

  6. C#开发BIMFACE系列32 服务端API之模型对比3:批量获取模型对比状态

    系列目录     [已更新最新开发文章,点击查看详细] 在<C#开发BIMFACE系列31 服务端API之模型对比2:获取模型对比状态>中介绍了根据对比ID,获取一笔记录的对比状态.由于模 ...

  7. ASP.NET Core技术研究-全面认识Web服务器Kestrel

    因为IIS不支持跨平台的原因,我们在升级到ASP.NET Core后,会接触到一个新的Web服务器Kestrel.相信大家刚接触这个Kestrel时,会有各种各样的疑问. 今天我们全面认识一下ASP. ...

  8. 当td中文字过长时,显示为省略号

    当表格中的文字过长时,可选择已省略号显示.这里是用js实现的.首先获取td中的文字长度(innerText.length),如果长度超过了设定的长度,则截取内容,加上省略号显示.示例代码如下: $(f ...

  9. RESTFul 设计规范

    REST这个词,是Roy Thomas Fielding博士在他2000年提出的,有兴趣的可以阅读一下他的论文, 论文地址为:http://www.ics.uci.edu/~fielding/pubs ...

  10. TensorFlow keras读取图片

    from tensorflow.python.keras.preprocessing.image import load_img,img_to_array def main(): #tagert_si ...