陈同学
微服务
Accelerator
About
# SpringBoot 中 @EnableWebMvc 导致 Converter 失效 ## 问题现象 某SpringBoot应用在自定义的 **ObjectMapper** 中设置了日期反序列化工具DateDeserializer。在 DispatchServlet 解析参数时 **org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter** 中会用到反序列化工具。 ```java @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper serializingObjectMapper() { ObjectMapper mapper = new ObjectMapper(); JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addDeserializer(Date.class, new DateDeserializer()); ... } ``` 应用在引入某个custom starter 后,这些工具突然都失效了。例如在解析日期参数时出错: ```java 2019-02-11 16:32:35.903 WARN 5353 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.Date` from String "2019-02-11 09:31:30": not a valid representation (error: Failed to parse Date value '2019-02-11 09:31:30': Cannot parse date "2019-02-11 09:31:30": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSZ', parsing fails (leniency? null)) ``` ## 问题排查 引入的starter与其他starter的差别在于使用了 **@EnableWebMvc**,目的是为了设置一个HandlerInterceptor。 ```java @EnableWebMvc @Configuration public class XXXAutoConfiguration extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new XXXInterceptor()); } } ``` 将 **@EnableWebMvc** 去掉后,应用正常使用。 ## 问题原因 **原因:@EnableWebMvc** 导致SpringBoot中 WebMvc的自动配置失效。 `@EnableWebMvc ` 中 **Import** 了 DelegatingWebMvcConfiguration。 ```java @Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc { } ``` 而 DelegatingWebMvcConfiguration 继承于 WebMvcConfigurationSupport。 ```java @Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { } ``` 因此,IoC容器中已存在 WebMvcConfigurationSupport 的实例。 ```java @Configuration @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) public class WebMvcAutoConfiguration { } ``` 然而在 SpringBoot WebMvcAutoConfiguration中,`@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)` 与上面的配置冲突,导致不会处理WebMvcAutoConfiguration, `@EnableWebMvc` 标记的配置类将全面接管Spring MVC 的自动配置。 那为什么自定义的ObjectMapper也会失效呢? 在WebMvcAutoConfiguration中,会 **@Import(EnableWebMvcConfiguration.class)**。 ```java @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) public class WebMvcAutoConfiguration { @Configuration @Import(EnableWebMvcConfiguration.class) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware { } } ``` EnableWebMvcConfiguration中会注入RequestMappingHandlerAdapter。 ```java @Configuration public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration { @Bean @Override public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(); adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect()); return adapter; } } ``` 在 **super.requestMappingHandlerAdapter()** 时,调用如下方法,会设置 **HttpMessageConverters**。其中,MappingJackson2HttpMessageConverter 会使用文章最前面注入的 ObjectMapper。 ```java @Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); // 设置 MessageConverters adapter.setMessageConverters(getMessageConverters()); ... } ``` 因此,若使用了 **@EnableWebMvc** ,将导致 Converter 失效。
本文由
cyj
创作,可自由转载、引用,但需署名作者且注明文章出处。
文章标题:
SpringBoot 中 @EnableWebMvc 导致 Converter 失效
文章链接:
https://chenyongjun.vip/articles/101
扫码或搜索 cyjrun 关注微信公众号, 结伴学习, 一起努力