【轉】 Spring NoSuchBeanDefinitionException原因分析


摘要:本文譯自Eugen Paraschiv文章spring NoSuchBeanDefinitionException 原文鏈接: http://www.baeldung.com/spring-nosuchbeandefinitionexception 感謝Eugen Paraschiv對此所做的研究。

概述

在本文中,我將通過實例向你展示Spring 中org.springframework.beans.factory.NoSuchBeanDefinitionException 出現的原因。如果BeanFactory在Spring Context中沒有找到bean的實例,就會拋出這個常見的異常。

Cause: No qualifying bean of type […] found for dependency

這個異常的出現一般是因為需要注入的bean未定義 
有一個類BeanA.Java

package com.csdn.training.model; @Component public class BeanA { @Autowired private BeanB beanB; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

有一個類BeanB.java

package com.csdn.training.service; @Component public class BeanB { } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

配置文件applicationContext.xml

<context:component-scan base-package="com.csdn.training.model"></context:component-scan>
  • 1

用一個測試類去啟動拉起Spring容器:

package com.csdn.test; public class AppTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); BeanA beanA = (BeanA) context.getBean("beanA"); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

自動掃描包路徑缺少了BeanB,它和BeanA 不在同一路徑下 
如果依賴 IBusinessService 在Spring 上下文中沒有定義,引導進程報錯:No Such Bean Definition Exception.

nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.csdn.training.service.BeanB] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
  • 1

Spring會提示:”Expected at least 1 bean which qualifies as autowire candidate for this dependency“(依賴至少有一個備選的bean能被自動注入) 
出現異常的原因是IBusinessService 在上下文中不存在:如果bean是通過classpath自動掃描來裝配,並且IBusinessService已經正確的加上了注解(@Component,@Repository,@Service,@Controller等),也許是你沒有把正確的包路徑告訴Spring。

配置文件可以如下配置:

<context:component-scan base-package="com.csdn.training"></context:component-scan>
  • 1

如果bean不能自動被掃描到,而手動定義卻可以識別,那Bean就沒有在Spring上下文中定義。

Cause: No qualifying bean of type […] is defined

造成這一異常的原因可能是Spring上下文中存在兩個或以上該bean的定義。如果接口IService 有兩個實現類 ServiceImplA 和ServiceImplB 
接口:IService.java

package com.csdn.training.service; public interface IService { }
  • 1
  • 2
  • 3
  • 4
  • 5

兩個實現類:ServiceImplA.java

package com.csdn.training.service; import org.springframework.stereotype.Service; @Service public class ServiceImplA implements IService { }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

ServiceImplB.java

package com.csdn.training.service; import org.springframework.stereotype.Service; @Service public class ServiceImplB implements IService { }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果BeanA 自動注入這一接口,Spring就無法分辨到底注入哪一個實現類:

package com.csdn.training.model; import com.csdn.training.service.IService; @Component public class BeanA { @Autowired private IService serviceImpl; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

然后,BeanFactory就拋出異常NoSuchBeanDefinitionException 
Spring會提示:”expected single matching bean but found 2“(只應該匹配一個bean但是找到了多個)

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.csdn.training.service.IService] is defined: expected single matching bean but found 2: serviceImplA,serviceImplB
  • 1
  • 2
  • 3

上例中,有時你看到的異常信息是NoUniqueBeanDefinitionException,它是NoSuchBeanDefinitionException 它的子類,在Spring 3.2.1中,修正了這一異常,為的是和bean未定義這一異常區分開。

nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.csdn.training.service.IService] is defined: expected single matching bean but found 2: serviceImplA,serviceImplB
  • 1

解決這一異常可以用注解@Qualifier 來指定想要注入的bean的名字。

package com.csdn.training.model; import com.csdn.training.service.IService; @Component public class BeanA { @Autowired @Qualifier("serviceImplA") private IService serviceImpl; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

修改以后,Spring就可以區分出應該注入那個bean的實例,需要注意的是ServiceImplA的默認實例名稱是serviceImplA

Cause: No Bean Named […] is defined

當你通過具體的bean的名字去得到一個bean的實例的時候,如果Spring 沒有在上下文中找到這個bean,就會拋出這個異常。

package com.csdn.test; public class AppTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); context.getBean("beanX"); } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

這個例子中,沒有一個bean被定義成 “beanX”,就會拋出如下異常: 
Spring會提示:”No bean named XXX is defined” (沒有找到一個名叫XXX的bean)

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'beanX' is defined at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition
  • 1

Cause: Proxied Beans

如果bean由JDK的動態代理機制所管理,那么代理將不會繼承該bean,它只會實現與其相同的接口。因此,如果bean是通過接口注入的,就可以成功注入。如果通過其實現類注入,Spring就無法將bean實例與類關聯,因為代理並不真正的繼承於類。 
出現這一原因,很有可能是因為你使用了Spring的事物,在bean上使用了注解@Transactional 
如下,ServiceA注入了ServiceB,這兩個service都使用了事物,通過實現類注入bean就不起作用了。 
借口IService.java無變化,其實現類加上事物的注解 
ServiceImplA.java

package com.csdn.training.service; @Service @Transactional public class ServiceImplA implements IService { @Autowired private ServiceImplB serviceImplB; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

ServiceImplB.java

package com.csdn.training.service; @Service @Transactional public class ServiceImplB implements IService { }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果改成通過接口注入,就可以:

ServiceImpl.java

package com.csdn.training.service; @Service @Transactional public class ServiceImplA implements IService { @Autowired @Qualifier("serviceImplB") private IService serviceImplB; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

結論

本文通過幾個小例子,分析了NoSuchBeanDefinitionException 用了這一異常可能出現的情形,對於我們在實際開發過程中定位錯誤提供了一定的參考。 
原文為英文版,我在原文的基礎上稍作改動,但又盡量保持原文的精髓,如果對譯文有異議,歡迎指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM