expected single matching bean but found 2

expected single matching bean but found 2


异常场景:

  1. 单元测试
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:test-application-context.xml")
public class TcActConsumer {

    @Autowired
    //@Resource(name = "rpcDemoServiceImpl")
    private RpcDemoService rpcDemoService;
    @Test
    public void testSelect(){
        String select = this.rpcDemoService.select();
        log.info(select);
    }
}
  1. 运行结果

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘com.demo.TestConsumer’: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.demo.service.RpcDemoService com.demo.TestConsumer.rpcDemoService; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.demo.service.RpcDemoService] is defined: expected single matching bean but found 2: rpcDemoServiceImpl,demoService
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:384)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:331)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:213)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:290)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:292)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner 2. e v a l u a t e ( P a r e n t R u n n e r . j a v a : 268 ) a t o r g . s p r i n g f r a m e w o r k . t e s t . c o n t e x t . j u n i t 4. s t a t e m e n t s . R u n B e f o r e T e s t C l a s s C a l l b a c k s . e v a l u a t e ( R u n B e f o r e T e s t C l a s s C a l l b a c k s . j a v a : 61 ) a t o r g . s p r i n g f r a m e w o r k . t e s t . c o n t e x t . j u n i t 4. s t a t e m e n t s . R u n A f t e r T e s t C l a s s C a l l b a c k s . e v a l u a t e ( R u n A f t e r T e s t C l a s s C a l l b a c k s . j a v a : 71 ) a t o r g . j u n i t . r u n n e r s . P a r e n t R u n n e r . r u n ( P a r e n t R u n n e r . j a v a : 363 ) a t o r g . s p r i n g f r a m e w o r k . t e s t . c o n t e x t . j u n i t 4. S p r i n g J U n i t 4 C l a s s R u n n e r . r u n ( S p r i n g J U n i t 4 C l a s s R u n n e r . j a v a : 176 ) a t o r g . j u n i t . r u n n e r . J U n i t C o r e . r u n ( J U n i t C o r e . j a v a : 137 ) a t c o m . i n t e l l i j . j u n i t 4. J U n i t 4 I d e a T e s t R u n n e r . s t a r t R u n n e r W i t h A r g s ( J U n i t 4 I d e a T e s t R u n n e r . j a v a : 68 ) a t c o m . i n t e l l i j . r t . e x e c u t i o n . j u n i t . I d e a T e s t R u n n e r 2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner 2.evaluate(ParentRunner.java:268)atorg.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)atorg.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)atorg.junit.runners.ParentRunner.run(ParentRunner.java:363)atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)atorg.junit.runner.JUnitCore.run(JUnitCore.java:137)atcom.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)atcom.intellij.rt.execution.junit.IdeaTestRunnerRepeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.demo.service.RpcDemoService com.demo .TestConsumer.rpcDemoService; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.demo .service.RpcDemoService] is defined: expected single matching bean but found 2: rpcDemoServiceImpl,demoService
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor A u t o w i r e d F i e l d E l e m e n t . i n j e c t ( A u t o w i r e d A n n o t a t i o n B e a n P o s t P r o c e s s o r . j a v a : 508 ) a t o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . a n n o t a t i o n . I n j e c t i o n M e t a d a t a . i n j e c t ( I n j e c t i o n M e t a d a t a . j a v a : 87 ) a t o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . a n n o t a t i o n . A u t o w i r e d A n n o t a t i o n B e a n P o s t P r o c e s s o r . p o s t P r o c e s s P r o p e r t y V a l u e s ( A u t o w i r e d A n n o t a t i o n B e a n P o s t P r o c e s s o r . j a v a : 289 ) . . . 25 m o r e C a u s e d b y : o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . N o U n i q u e B e a n D e f i n i t i o n E x c e p t i o n : N o q u a l i f y i n g b e a n o f t y p e [ c o m . d e m o . s e r v i c e . R p c D e m o S e r v i c e ] i s d e f i n e d : e x p e c t e d s i n g l e m a t c h i n g b e a n b u t f o u n d 2 : r p c D e m o S e r v i c e I m p l , d e m o S e r v i c e a t o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . s u p p o r t . D e f a u l t L i s t a b l e B e a n F a c t o r y . d o R e s o l v e D e p e n d e n c y ( D e f a u l t L i s t a b l e B e a n F a c t o r y . j a v a : 970 ) a t o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . s u p p o r t . D e f a u l t L i s t a b l e B e a n F a c t o r y . r e s o l v e D e p e n d e n c y ( D e f a u l t L i s t a b l e B e a n F a c t o r y . j a v a : 858 ) a t o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . a n n o t a t i o n . A u t o w i r e d A n n o t a t i o n B e a n P o s t P r o c e s s o r AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289) ... 25 more Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.demo.service.RpcDemoService] is defined: expected single matching bean but found 2: rpcDemoServiceImpl,demoService at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:970) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)atorg.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)...25moreCausedby:org.springframework.beans.factory.NoUniqueBeanDefinitionException:Noqualifyingbeanoftype[com.demo.service.RpcDemoService]isdefined:expectedsinglematchingbeanbutfound2:rpcDemoServiceImpl,demoServiceatorg.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:970)atorg.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessorAutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
… 27 more


异常排查

  1. IDEA 编辑器中鼠标放置在 RPCDemoService rpcDemoService ; rpcDemoService对象上提示如下信息

Could not autowire. There is more than one bean of ‘RpcDemoService’ type.
Beans:
demoService (provider.xml)
rpcDemoServiceImpl (RpcDemoServiceImpl.java)

  1. 提示按照类型加载时有两处无法确认具体加载内容

异常分析

  1. 为何出现两个对象
    1. 全文检索 RpcDemoService

      1. 同时放入了两个文件中
      2. dubbo 的 consumer.xml 与 provider.xml 中均有此接口的配置
      3. 配置的接口id不同,是否会是此处产生的影响?
      4. 注释掉 consumer.xml 中对该接口的配置
      5. 再次运行依然报错
      6. dubbo 注入接口仅根据 id 进行区分,不会产生影响
    2. provider.xml 中接口的配置 id = demoService 而非 接口名称首字母小写

      1. 历史原因,类名小写的配置先写到了 consumer.xml 中,应该是为了功能测试,再写 provider.xml 时发现已经被占用了,所以命名时不是类名小写
      2. 修改后,重新启动,接口运行成功
      3. 初步定位问题的原因是 provider.xml 中注入接口的id值没有使用接口类名称首字母小写的命名方式

异常修复

  1. 将 @Autowired 注入改为 @Resource(name=“rpcXXXServiceImpl”)
  2. 修改 dubbo-provider.xml
    将 ref 与 id 的配置值改为 demoService 改为 rpcDemoService



异常原因

  1. Autowired默认先按byType,如果发现找到多个bean,则又按照byName方式比对,如果还有多个,则报出异常
  2. 将 id 值由 demoService 改为 rpcDemoService ,则 provider.xml 中的该类型的名称为 rpcDemoService
  3. rpcDemoServiceImpl 指向的接口默认id即为 接口类名称小写,所以两者具有了相同的 id 名称
  4. bean 的名称具有唯一性
  5. 为何是两个注入
    1. demoService (provider.xml) dubbo 注入
    2. rpcDemoServiceImpl (RpcDemoServiceImpl.java) spring 注入
    3. provider.xml 是放置到 Spring 的配置文件中,由 spring 管理
    4. 未修改前,是两个不通的id值,所示是两个不同的配置对象,是根据 id 进行区分的

他山之石

  1. @Autowired 注入同一个 bean 一次1
@Autowired
private RpcDemoService rpcDemoService ;
@Autowired
private RpcDemoService demoService ;
// 接口中同时调用 rpcDemoService demoService 就会报上述异常
  1. 注解对比2
名称 所属 注入对象
@Resource Spring 本地spring容器中的对象
@Autowired Java 本地spring容器中的对象
@Resource Dubbo 分布式中的远程服务对象
  1. 按名称注入
	@Autowired
	@Qualifier("rpcDemoServiceImpl" )
	等于
	@Resource(name="rpcDemoServiceImpl")

其他方式

  1. IDEA中添加异常断点3
    1. ctrl+shif+f8
    2. 指定异常类型进行拦截,通过对主线程的堆栈信息的分析,定位具体的问题原因
    3. 添加拦截异常:NoUniqueBeanDefinitionException
    4. 再次执行异常方法,程序启动定位到异常信息,查看main线程堆栈信息
  2. 运行结果如图
  3. 从跟踪信息中可以查看到发生歧义的加载类型的路径及名称

心得体会

  1. dubbo provider.xml 中注入接口时,id值一定为接口类名称首字母小写
  2. 断点异常调试,能够快速定位问题及异常信息栈;尤其是针对项目启动时出现的异常,无法断点调试的问题

  1. Spring的@Autowired注入规则 ↩︎

  2. spring @Autowire 的注解默认是按类型注入bean ↩︎

  3. IntelliJ IDEA如何添加异常断点 ↩︎

你可能感兴趣的:(#,异常汇总)