原理:WebMvcConfigurer 与 WebMvcConfigurationSupport避坑指南

x33g5p2x  于2022-06-20 转载在 其他  
字(4.7k)|赞(0)|评价(0)|浏览(315)

源码地址(包含所有与springmvc相关的,静态文件路径设置,request请求入参接受,返回值处理converter设置等等):

spring-framework/WebMvcConfigurationSupport.java at b595dc1dfad9db534ca7b9e8f46bb9926b88ab5a · spring-projects/spring-framework · GitHub

https://github.com/spring-projects/spring-framework/blob/b595dc1dfad9db534ca7b9e8f46bb9926b88ab5a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.javaspring-framework/DelegatingWebMvcConfiguration.java at b595dc1dfad9db534ca7b9e8f46bb9926b88ab5a · spring-projects/spring-framework · GitHub

https://github.com/spring-projects/spring-framework/blob/b595dc1dfad9db534ca7b9e8f46bb9926b88ab5a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java

(1)这种方式我们只要创建一个类继承 WebMvcConfigurer

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

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

  • 实现WebMvcConfigurer  
  • 继承WebMvcConfigurationSupport

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

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

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

| <br>1<br> | <br>@ConditionalOnMissingBean``(WebMvcConfigurationSupport.``class``)<br> |

看到这行可以明白,原来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,我们来看一下源代码:

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

| <br>1<br><br>2<br><br>3<br><br>4<br><br>5<br><br>6<br><br>7<br><br>8<br> | <br>@Bean<br><br>        ``@ConditionalOnMissingBean<br><br>        ``public StringHttpMessageConverter stringHttpMessageConverter() {<br><br>            ``StringHttpMessageConverter converter = ``new StringHttpMessageConverter(<br><br>                    ``this``.encodingProperties.getCharset());<br><br>            ``converter.setWriteAcceptCharset(``false``);<br><br>            ``return converter;<br><br>        ``}<br> |

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

| <br>1<br><br>2<br><br>3<br><br>4<br><br>5<br><br>6<br><br>7<br><br>8<br><br>9<br><br>10<br><br>11<br><br>12<br><br>13<br><br>14<br><br>15<br><br>16<br><br>17<br><br>18<br><br>19<br><br>20<br><br>21<br> | <br>@Configuration<br><br>public class WebConfiguration ``extends WebMvcConfigurationSupport {<br><br>    ``@Autowired<br><br>    ``private StringHttpMessageConverter stringHttpMessageConverter;<br><br>    ``@Autowired<br><br>    ``private MappingJackson2HttpMessageConverter httpMessageConverter;<br><br>    ``/**<br><br>     ``* 添加转换器<br><br>     ``*/<br><br>    ``@Override<br><br>    ``public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {<br><br>        ``for (``int i = ``0``; i < converters.size(); i++) {<br><br>            ``if (converters.get(i) ``instanceof StringHttpMessageConverter){<br><br>                ``converters.set(i, stringHttpMessageConverter);<br><br>            ``}<br><br>            ``if (converters.get(i) ``instanceof MappingJackson2HttpMessageConverter) {<br><br>                ``converters.set(i, httpMessageConverter);<br><br>            ``}<br><br>        ``}<br><br>    ``}<br><br>}<br> |

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

补充_

WebMvcConfigurer类代码分析:

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

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

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

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

相关文章