HttpMessageConverter 自动配置过程分析
HttpMessageConverter 自动配置过程分析
第一步:所有 WebMvcConfigurer 实现类注册到 Spring 容器中
一般来说,容器中至少会会注册 WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter 这个实现类。
如果有 SpringMVC 定制化的需求,那么我们自己实现的 WebMvcConfigurer 也会注册到容器中,从而 Spring 容器中包含多个 WebMvcConfigurer 实现类。
第二步:WebMvcAutoConfiguration$EnableWebMvcConfiguration 自动装配其父类 DelegatingWebMvcConfiguration 属性 configurers
DelegatingWebMvcConfiguration 的 configurers 属性是 WebMvcConfigurerComposite 类型,该属性被配置为自动装配:
1 |
|
WebMvcConfigurerComposite 也是 WebMvcConfigurer 的实现类,只不过它没有注册到容器中,它的主要作用是,保存整个 Spring 容器中注册的所有 WebMvcConfigurer 实现类。
1 | class WebMvcConfigurerComposite implements WebMvcConfigurer { |
内部类 EnableWebMvcConfiguration 的父类是 DelegatingWebMvcConfiguration。DelegatingWebMvcConfiguration 的父类是 WebMvcConfigurationSupport。
1 |
|
第三步:WebMvcAutoConfiguration$EnableWebMvcConfiguration 注册一些 SpringMVC 组件,比如 RequestMappingHandlerAdapter,注册时需要调用 getMessageConverters() 获取 HttpMessageConverter 并设置到组件的内部属性中。
1 |
|
1 | public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware { |
第四步 遍历容器中所有已注册的 WebMvcConfigurer,依次调用各自 configureMessageConverters 实现,来对 this.messageConverters 进行配置
configureMessageConverters(this.messageConverters); 执行动态绑定到 DelegatingWebMvcConfiguration 的实现
1 | // DelegatingWebMvcConfiguration |
WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter 执行 configureMessageConverters
一般来说,WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter 会在 this.delegates 中排在最前面,也即会首先调用其 configureMessageConverters 实现:
1 | // WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter |
this.messageConvertersProvider 是 ObjectProvider<HttpMessageConverters> 类型,它是 WebMvcAutoConfigurationAdapter 构造方法时传入的,用于延迟对从容器中查找和创建 HttpMessageConverters 的操作。
直到在 configureMessageConverters 方法中调用 ifAvailable 方法时,才会尝试从容器中获取一个 HttpMessageConverters 对象。
获取到以后,就将该对象内部保存的所有 HttpMessageConverter 获取到,最后添加到 WebMvcConfigurationSupport#messageConverters 中。
1 | default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException { |
HttpMessageConverters 是何时注册到容器中的呢?是 HttpMessageConvertersAutoConfiguration 这个自动配置类注册进去的:
1 |
|
能看到,这里也使用了 ObjectProvider,只不过延迟查找的类型是 HttpMessageConverter 而不是 HttpMessageConverters。
方法内部就是简单地调用了 HttpMessageConverters 的有参构造器,唯一的构造参数是通过 ObjectProvider 查找出此时 Spring 容器中所有的 HttpMessageConverter 并封装为 List 集合传入。
回顾之前在 SpringMVC 中说过的,SpringBoot 会自动配置两个 StringHttpMessageConverter,其中默认编码为 UTF-8 的 StringHttpMessageConverter 就是在这里先从容器中获取到,然后作为构造参数传递给 HttpMessageConverters 的构造方法的。

1 | public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>> { |
我们来看一下 getDefaultConverters() 获取到哪些转换器
1 | private List<HttpMessageConverter<?>> getDefaultConverters() { |
该方法主要是检查 WebMvcConfigurationSupport 类是否存在,如果存在,就调用该类中的成员方法 getMessageConverters() 获取默认转换器。
这里写法奇怪的原因是,WebMvcConfigurationSupport#getMessageConverters 是个成员方法,因此创建了一个匿名内部类对象,再调用 super.getMessageConverters 来实现调用。
1 | // WebMvcConfigurationSupport |
很眼熟,兜兜转换,我们又回到了 getMessageConverters 方法。但要注意,该方法是一个成员方法!
之前,是 WebMvcAutoConfiguration$EnableWebMvcConfiguration 调用的,目的是为注册 RequestMappingHandlerAdapter 组件时,设置适配器组件内部的转换器属性。
这里,是一个 WebMvcConfigurationSupport 的匿名内部类调用的,该匿名内部类没有重写任何方法,因此调用 getMessageConverters 方法时,方法内部的 configureMessageConverters 和 extendMessageConverters,均保持为 WebMvcConfigurationSupport 的空实现版本,什么都不干。
也就是说,只有 addDefaultHttpMessageConverters(this.messageConverters); 会起作用,addDefaultHttpMessageConverters 在 WebMvcConfigurationSupport 有实现。
1 | protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) { |
WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter 执行 configureMessageConverters 方法的整个过程分析完毕,小结一下。
其实整个过程就是从容器中获取 HttpMessageConverters 对象,然后取出该对象内部保存的所有 HttpMessageConverter 添加到 WebMvcAutoConfiguration$EnableWebMvcConfiguration 的 messageConverters 属性中去。
HttpMessageConverters 内部的 HttpMessageConverter 来自两个地方:一是 Spring 容器中已注册的,二是 WebMvcConfigurationSupport 类的 addDefaultHttpMessageConverters 设置的默认转换器。
既然 HttpMessageConverters 内部的 HttpMessageConverter 可以来自 Spring 容器中已注册的,那么我们想要自定义 HttpMessageConverter,其实也可以将我们的自定义 HttpMessageConverter 直接注册到 Spring 容器中!
自定义 WebMvcConfigurer 实现类执行 configureMessageConverters 方法
1 |
|
注意,这里传入的 converters 参数,就已经包含了 WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter 在执行 configureMessageConverters 时添加进去的一些转换器。
第五步:如果遍历所有已注册的 WebMvcConfigurer 执行 configureMessageConverters,仍然没有配置任何 HttpMessageConverter 到 this.messageConverters 中,此时添加默认 HttpMessageConverter 到 this.messageConverters 中
1 | protected final List<HttpMessageConverter<?>> getMessageConverters() { |
一般来说,第五步不会执行。
第六步:遍历容器中所有已注册的 WebMvcConfigurer,依次调用各自 extendMessageConverters 实现,来对 this.messageConverters 进行配置
同样地,一般来说,WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter 会在 this.delegates 中排在最前面,也即会首先调用其 extendMessageConverters 实现。
不过 WebMvcAutoConfigurationAdapter 没有实现 extendMessageConverters 方法,因此保持为 WebMvcConfigurer 的默认接口空实现。
然后是,自定义 WebMvcConfigurer 实现类执行 extendMessageConverters 方法来添加转换器配置。
疑问:configureMessageConverters 与 extendMessageConverters 的区别
这里我有一个疑问是,configureMessageConverters 似乎和 extendMessageConverters 的功能是有些重合的,都能做 HttpMessageConverter 的配置,为什么 WebMvcConfigurer 接口中要同时提供这两个接口方法呢?
1 | public interface WebMvcConfigurer { |
官方建议我们使用 extendMessageConverters 来添加自定义转换器或者修改已配置的转换器;若使用 configureMessageConverters 来添加转换器,会关闭默认转换器的注册工作,也就是关闭 addDefaultHttpMessageConverters 的执行。
前半句可以记下来,但是后半句感觉有问题。
我们再回过头来看 getMessageConverters() 的代码:
1 | protected final List<HttpMessageConverter<?>> getMessageConverters() { |
我们自定义 WebMvcConfigurer 实现类,并调用 configureMessageConverters 添加转换器,确实会导致 this.messageConverters 不为空,从而 addDefaultHttpMessageConverters 不执行。
但问题是,WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapte 本身也向 this.messageConverters 中添加了一堆转换器(其中就包括默认的转换器),也就是说,就算我们不做定制化,addDefaultHttpMessageConverters 一样是不会执行的。
我猜测,官方说的“使用 configureMessageConverters 来添加转换器会关闭默认转换器的注册工作,也就是关闭 addDefaultHttpMessageConverters 的执行”,应该指的是我们全面接管 SpringMVC 的定制化场景,而不是我们现在的通过 WebMvcConfigurer 进行 SpringMVC 定制化的场景。