Spring IoC管理疑问:自定义XmlMapper覆盖默认ObjectMapper致接口解析异常
这问题我之前排查过,核心和Spring Boot的Jackson自动配置逻辑直接相关,具体原因可以拆成两点来看:
XmlMapper是ObjectMapper的子类
Jackson的XmlMapper继承自ObjectMapper,当你通过@Bean定义了一个XmlMapper实例后,Spring容器中就存在了一个ObjectMapper类型的Bean。而Spring Boot的JacksonAutoConfiguration自动配置类有个关键逻辑:如果容器中已经存在ObjectMapper类型的Bean,就不会再创建默认的、用于JSON处理的ObjectMapper实例。Web层消息转换器的依赖逻辑
Spring MVC的MappingJackson2HttpMessageConverter(负责处理JSON格式的请求/响应)和MappingJackson2XmlHttpMessageConverter(负责XML格式)都会依赖容器中的ObjectMapper类型Bean。当默认的JSON用ObjectMapper被你的XmlMapper替代后,MappingJackson2HttpMessageConverter也会使用这个XmlMapper来处理请求,导致RestController默认会按照XML格式解析请求体,自然就出现了你遇到的问题。
解决办法
这里提供两种常用的解决方案,你可以根据自己的需求选择:
方案一:单独配置XML消息转换器(推荐)
不要直接定义XmlMapper的Bean,而是创建MappingJackson2XmlHttpMessageConverter的Bean并传入XmlMapper,这样既保留了默认的JSON ObjectMapper,又能支持XML格式的处理:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public MappingJackson2XmlHttpMessageConverter xmlHttpMessageConverter() { return new MappingJackson2XmlHttpMessageConverter(new XmlMapper()); } }
方案二:给XmlMapper Bean指定自定义名称
如果你确实需要单独的XmlMapper Bean供其他地方使用,可以给它指定一个唯一的名称,这样Spring Boot会继续创建默认的ObjectMapper:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean("customXmlMapper") public XmlMapper xmlMapper() { return new XmlMapper(); } }
之后在需要使用这个XmlMapper的地方,通过@Qualifier("customXmlMapper")来注入即可,Web层依然会用默认的ObjectMapper处理JSON请求。
内容的提问来源于stack exchange,提问作者Romas Augustinavičius

