注入冲突问题
新项目启动,报错是在创建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.doResolveDependency
的1397
行Map<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
方法可以看到,排序的逻辑是:
- 首先按类名称升序排序,其中名称是全称,比如
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
- 接着按
@AutoConfigureOrder
注解升序排序,范围是[Integer最小值, Integer最大值],没加注解或不指定值则默认为0
。 - 最后按@AutoConfigureAfter和@AutoConfigureBefore调整顺序。
解决问题
最后回到问题上,在自定义创建ObjectMapper的Configuration
类上加上@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
,最终启动成功。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。