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. 爬取腾讯网的热点新闻文章 并进行词频统计(Python爬虫+词频统计)

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:一棵程序树 PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...

  2. Linux下安装Redis4.0版本(简便方法)

    Redis介绍: Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久 ...

  3. c++ find 函数与count函数

    1 algorithml中的find,还有就是string中的find 对对于第一种其调用形式为 find(start,end,value) start搜寻的起点,end搜寻的终点,要寻找的value ...

  4. Java核心技术--接口与内部类

    接口implement 继承接口,即履行"义务". 接口中所有的方法自动属于public,在接口声明中,不必提供关键字public 接口中决不能含有实例域,也不能在接口中实现方法 ...

  5. [javascript]JS获取当前时间戳的方法

    JavaScript 获取当前时间戳: 第一种方法:(这种方法只精确到秒) var timestamp = Date.parse(new Date()); 结果:1280977330000 第二种方法 ...

  6. JAVA快速排序代码实现

    通过一趟排序将要排序的数据分割成独立的两部分:分割点左边都是比它小的数,右边都是比它大的数.然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列. 快速 ...

  7. .Net Core主机配置

    Host:(主机)负责web应用程序的启用和生成期管理,配置服务器和请求处理管道. 主机配置日志,依赖注入关系,实际上是一个封装了应用资源的对象. 创建主机生成器-〉配置主机-〉创建主机-〉运行主机. ...

  8. Service Location Protocol SLP

    https://www.ibm.com/developerworks/cn/linux/l-slp/ 服务发现(service discovery) 是在网络环境中发现必须使用的服务的能力.例如,如果 ...

  9. java中ThreadLocalRandom的使用

    java中ThreadLocalRandom的使用 在java中我们通常会需要使用到java.util.Random来便利的生产随机数.但是Random是线程安全的,如果要在线程环境中的话就有可能产生 ...

  10. zoj_2511 Design T-Shirt 贪心

    Design T-Shirt Time Limit: 2 Seconds      Memory Limit: 32768 KB Soon after he decided to design a T ...