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从零开始基础入门——开发环境搭建:Visual Studio Code

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

  2. 遇到自己喜欢的视频无法下载,python帮你解决

    问题描述 python是一种非常好用的爬虫工具.对于大多数的爬虫小白来说,python是更加简洁,高效的代码.今天就用实际案例讲解如何爬取动态的网站视频. 环境配置:python3:爬虫库reques ...

  3. JavaScript数据类型 —— 基础语法(2)

    JavaScript基础语法(2) 数据类型 js中有六种数据类型,包括五种基本数据类型(Number,String,Boolean,Undefined,Null),和一种复杂数据类型(Object) ...

  4. vue2.x学习笔记(十)

    接着前面的内容:https://www.cnblogs.com/yanggb/p/12584237.html. 事件处理 使用javascript当然少不了事件处理,即使是vue也不会例外. 监听事件 ...

  5. requets中urlencode的问题

    前言 今天团队群里有师傅问requests怎么设置不解码,这里是语误,其实师傅想说的是,如果设置不编码. 一开始我没懂,然后师傅们解答了这个问题后,我想了会儿懂了. 在一些CTF题目中,可能会碰到这样 ...

  6. beanshell 常用的内置变量与函数

    官方详细文档:https://github.com/beanshell/beanshell/wiki log:用来记录日志文件 log.info("jmeter"); vars - ...

  7. 这份Mybatis总结,我觉得你很需要!

    前言 只有光头才能变强. 文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y Mybatis应该是国内用得最多的「数据访问层」 ...

  8. UML 建模工具的安装与使用

    一. 实验目的1) 学习使用 EA(Enterprise Architect) 开发环境创建模型的一般方法: 2) 理解 EA 界面布局和元素操作的一般技巧: 3) 熟悉 UML 中的各种图的建立和表 ...

  9. kafka相关术语名词

    Topic:标签名,一个消息队列的名称 Producer:生产者,发布消息 Consumer:消费者,订阅发布消息,进行处理的存在 Broker:kafka集群,有一个.多个Topic Partiti ...

  10. QT踩坑记录1-Q_OBJECT编译问题

    QT踩坑记录1-Q_OBJECT编译问题 QTC++Bugs 错误输出 Q_OBJECT 宏错误的地方会编译出现这样的错误, 无法找到.... 由于自己不想再看到这个错误, 此处 复制自 参考连接1, ...