欢迎访问陈同学博客原文
某SpringBoot应用在自定义的 ObjectMapper 中设置了日期反序列化工具DateDeserializer。在 DispatchServlet 解析参数时 org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter 中会用到反序列化工具。
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper serializingObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(Date.class, new DateDeserializer());
...
}
应用在引入某个custom starter 后,这些工具突然都失效了。例如在解析日期参数时出错:
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。
@EnableWebMvc
@Configuration
public class XXXAutoConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new XXXInterceptor());
}
}
将 @EnableWebMvc 去掉后,应用正常使用。
原因:@EnableWebMvc 导致SpringBoot中 WebMvc的自动配置失效。
@EnableWebMvc
中 Import 了 DelegatingWebMvcConfiguration。
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
而 DelegatingWebMvcConfiguration 继承于 WebMvcConfigurationSupport。
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
因此,IoC容器中已存在 WebMvcConfigurationSupport 的实例。
@Configuration
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
public class WebMvcAutoConfiguration {
}
然而在 SpringBoot WebMvcAutoConfiguration中,@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
与上面的配置冲突,导致不会处理WebMvcAutoConfiguration, @EnableWebMvc
标记的配置类将全面接管Spring MVC 的自动配置。
那为什么自定义的ObjectMapper也会失效呢?
在WebMvcAutoConfiguration中,会 @Import(EnableWebMvcConfiguration.class)。
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
public class WebMvcAutoConfiguration {
@Configuration
@Import(EnableWebMvcConfiguration.class)
public static class WebMvcAutoConfigurationAdapter
implements WebMvcConfigurer, ResourceLoaderAware {
}
}
EnableWebMvcConfiguration中会注入RequestMappingHandlerAdapter。
@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。
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
// 设置 MessageConverters
adapter.setMessageConverters(getMessageConverters());
...
}
因此,若使用了 @EnableWebMvc ,将导致 Converter 失效。
欢迎关注陈同学的公众号,一起学习,一起成长