背景
在我的项目中,需要使用多个ObjectMapper,SpringBoot默认的ObjectMapper用于后端返回json格式的序列化,这部分的配置可以在配置文件中配置。同时需要另外提供定制化ObjectMapper用于序列化反序列化第三方接口对接。
问题
当我使用@Configuration+@Bean自定义ObjectMapper后,我发现配置文件所有对jackson的配置均失效,一通排查后发现是SpringBoot在创建原生ObjectMapper时,有个@ConditionOnMissingBean注解
@Bean
@Primary
//该注解的作用就是,当项目中不存在其他ObjectMapper时才会走这步,而我们自定义之后,自然而然不会走这不,也就是配置文件失效的原因
@ConditionalOnMissingBean
ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
return builder.createXmlMapper(false).build();
}
该注解的作用就是,当项目中不存在其他ObjectMapper时才会走这步,而我们自定义之后,自然而然不会走这不,也就是配置文件失效的原因
问题修复
网络上一堆一模一样的答案,均无效,只要你使用@Bean注解自定义,必定无效,因为SpringBoot在初始化过程中,先加载BeanDefinition,而不是直接初始化,所以无论添加@Order,@ConditionOnBean注解,均无效。
排查过后,发现有两种解决方案
- 在SpringBoot启动成功后,也就是主函数执行结束后,手动添加,此时springboot初始化流程已经走完,此时添加将不会检查
ApplicationContext run = SpringApplication.run(OriginalCircleStarter.class, args);
BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) run;
beanDefinitionRegistry.registerBeanDefinition("customObjectMapper", new RootBeanDefinition(ObjectMapper.class));
- 复制一份ObjectMapper(推荐)
SpringBoot为我们封装了创建ObjectMapper的builder,其中有我们配置文件中的配置项,我们直接builder后相当于复制了一份。而后就不冲突
/**
* 此处的ObjectMapper是springboot默认提供的ObjectMapper的复制品
* 原因:当项目中一旦自定义objectMapper时,springboot提供的将会失效,因为原生上有@ConditionOnMissingBean注解,导致自定义后,
* 原生的将不会被初始化,此时配置文件配置的一切将会失效,因此,我们解决办法为,复制一份
* @param jackson2ObjectMapperBuilderCustomizer 可理解为配置文件中属性配置
* @param jackson2ObjectMapperBuilder objectMapper构建器
* @return
*/
@Bean
@Primary
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer,
Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder){
//将springboot配置文件中的配置构建进builder中
jackson2ObjectMapperBuilderCustomizer.customize(jackson2ObjectMapperBuilder);
return jackson2ObjectMapperBuilder.build();
}
@Bean
public ObjectMapper responseParse() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper;
}