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 定制化的场景。