SpringBoot 中 @EnableWebMvc 导致 Converter 失效

欢迎访问陈同学博客原文

问题现象

某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的自动配置失效。

@EnableWebMvcImport 了 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 失效。


欢迎关注陈同学的公众号,一起学习,一起成长

你可能感兴趣的:(工具)