注入冲突问题

新项目启动,报错是在创建mappingJackson2HttpMessageConverter对象时,出现以下问题:

more than one 'primary' bean found among candidates, No qualifying bean of type 'com.fasterxml.jackson.databind.ObjectMapper' available: more than one 'primary' bean found among candidates: [jacksonObjectMapper, objectMapper]

看异常是创建了两个com.fasterxml.jackson.databind.ObjectMapper对象,并且每个创建的方法都有primary注解。
通过spring启动时的断点跟踪来确认下,先在DefaultListableBeanFactory.doResolveDependency1397Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);上打上断点"mappingJackson2HttpMessageConverter".equals(beanName),发现匹配到的bean确实是两个。
其中objectMapper是项目自定义的对象,很重要无法去掉,那接下来就需要看下jacksonObjectMapper是在哪里创建的,并且是否可以去掉。
继续断点跟踪,从DefaultListableBeanFactory.doGetBeanNamesForType方法中得到RootBeanDefinition对象,知道是在JacksonAutoConfiguration#JacksonObjectMapperConfiguration类创建的,其中的是创建方法上有@ConditionalOnMissingBean,那说明这个注解失效了。

ConditionalOnMissingBean失效

为了确认是不是@ConditionalOnMissingBean失效,我们从@ConditionalOnMissingBean的判断类org.springframework.boot.autoconfigure.condition.OnBeanCondition入手。
在方法getMatchOutcome上打上断点metadata != null && metadata instanceof SimpleMethodMetadata && "jacksonObjectMapper".equals(((SimpleMethodMetadata) metadata).getMethodName()),持续debug,发现最后matchResult.isAnyMatched()的结果是false,也就是没匹配到其他bean,自己可以创建。
猜测是不是因为Bean创建的顺序呢?

自动装载顺序

从自动装载排序类AutoConfigurationImportSelector入手,跟进到方法AutoConfigurationSorter.getInPriorityOrder的结果可以看到每个Configuration类的顺序,可以看到自定义创建ObjectMapper的Configuration类确实排在JacksonAutoConfiguration,那要怎么调整顺序呢,从getInPriorityOrder方法可以看到,排序的逻辑是:

  1. 首先按类名称升序排序,其中名称是全称,比如org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
  2. 接着按@AutoConfigureOrder注解升序排序,范围是[Integer最小值, Integer最大值],没加注解或不指定值则默认为0
  3. 最后按@AutoConfigureAfter和@AutoConfigureBefore调整顺序。

解决问题

最后回到问题上,在自定义创建ObjectMapper的Configuration类上加上@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE),最终启动成功。


noname
317 声望51 粉丝

一只菜狗