WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南

我们知道,在Spring Boot 2.0后用自己的的配置类继承WebMvcConfigurerAdapter时,idea会提示这个类已经过时了。

通常情况下我们会采用下面两种代替方案:

  • 实现WebMvcConfigurer  
  • 继承WebMvcConfigurationSupport

但是继承WebMvcConfigurationSupport时发现会造成一些问题

在这之前,我们先看一下WebMvc自动配置类WebMvcAutoConfiguration的定义:

WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南_第1张图片

注意红框圈起来到这个关键语句:

1

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

看到这行可以明白,原来SpringBoot做了这个限制,只有当WebMvcConfigurationSupport类不存在的时候才会生效WebMvc自动化配置,WebMvc自动配置类中不仅定义了classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/等路径的映射,还定义了配置文件spring.mvc开头的配置信息等。

当 WebMvcAutoConfiguration 不生效时会导致以下几个问题:
1.WebMvcProperties 和 ResourceProperties 失效

因为两个配置类中的属性都在 WebMvcAutoConfiguration 中使用

当WebMvc自动配置失效(WebMvcAutoConfiguration自动化配置)时,会导致无法视图解析器无法解析并返回到对应的视图

解决方案:

1. 在SpringBoot1.X的版本中,我们可以继承自WebMvcConfigurerAdapter,覆盖想要实现的方法即可。

2. 但是在SpringBoot2.X的定义中,WebMvcConfigurerAdapter已经被定义为@Deprecated,我们来看一下源代码:

WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南_第2张图片

SpringBoot其实也已经告诉你WebMvcConfigurerAdapter自从Spring5.0版本开始已经不建议使用了,但是你可以实现WebMvcConfigurer并重写相关方法来达到类似的功能。

2.类路径上的 HttpMessageConverter 失效

如:StringHttpMessageConverterConfiguration、MappingJackson2HttpMessageConverter ,因为 HttpMessageConverters 中持有着所有HttpMessageConverter的实例, 在 WebMvcAutoConfigurationAdapter 中会注入 HttpMessageConverters ,因此当 WebMvcAutoConfigurationAdapter 不加载时,则会失效,间接的造成 spring.http.encoding.charset 与 spring.jackson.date-format 假象的失效。

如:StringHttpMessageConverter 会使用 spring.http.encoding.charset 配置, 默认编码为:ISO-8859-1

1

2

3

4

5

6

7

8

@Bean

        @ConditionalOnMissingBean

        public StringHttpMessageConverter stringHttpMessageConverter() {

            StringHttpMessageConverter converter = new StringHttpMessageConverter(

                    this.encodingProperties.getCharset());

            converter.setWriteAcceptCharset(false);

            return converter;

        }

解决方案
因为已知的配置类都已通过 @Bean 注册在容器中,那么我们可以在使用 WebMvcConfigurationSupport 时,通过 @Autowired 注入到配置类中,然后替换掉 WebMvcConfigurationSupport 默认的配置即可,如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

@Configuration

public class WebConfiguration extends WebMvcConfigurationSupport {

    @Autowired

    private StringHttpMessageConverter stringHttpMessageConverter;

    @Autowired

    private MappingJackson2HttpMessageConverter httpMessageConverter;

    /**

     * 添加转换器

     */

    @Override

    public void extendMessageConverters(List> converters) {

        for (int i = 0; i < converters.size(); i++) {

            if (converters.get(i) instanceof StringHttpMessageConverter){

                converters.set(i, stringHttpMessageConverter);

            }

            if (converters.get(i) instanceof MappingJackson2HttpMessageConverter) {

                converters.set(i, httpMessageConverter);

            }

        }

    }

}

也可以根据需求来重新实现。

 

补充_

WebMvcConfigurer类代码分析:

从EnableWebMvcConfiguration配置类开始,当它注入时父类会注入Spring容器中所有的WebMvcConfigurer类

WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南_第3张图片

 接着注入RequestMappingHandlerAdapter Bean 它会调用父类的requestMappingHandlerAdapter方法

WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南_第4张图片

 WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南_第5张图片

 

WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南_第6张图片

这个时候获取配置,例如自定义了返回结果Handler, WebMvcConfigurerComposite会遍历调用WebMvcConfigurer实现类的

addReturnValueHandlers方法,会把自定义配置加载到默认的配置中

你可能感兴趣的:(SpringBoot-原理)