1. 概述
在本教程中,我們將討論 <strong>Spring <em>org.springframework.beans.factory.BeanCreationException.</em></strong> 異常。 這是一個非常常見的異常,當 <em>BeanFactory</em> 創建 Bean 時,遇到問題並拋出。 本文將探討該異常的最常見原因,以及相應的解決方案。
2. 原因:org.springframework.beans.factory.NoSuchBeanDefinitionException
最常見的原因是 Spring 試圖注入不存在的 Bean,即在上下文中注入一個未定義的 Bean。
例如,BeanA 試圖注入 BeanB:
@Component
public class BeanA {
@Autowired
private BeanB dependency;
...
}如果未在上下文中找到 BeanB,則將拋出以下異常(創建 Bean 錯誤):
Error creating bean with name 'beanA': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.baeldung.web.BeanB cpm.baeldung.web.BeanA.dependency;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.baeldung.web.BeanB] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}為了診斷此類問題,我們首先需要確保 Bean 已聲明:
- 要麼在 XML 配置文件中使用 <bean /> 元素
- 要麼在 Java 的 @Configuration 類中通過 @Bean 註解
- 或者使用 @Component、@Repository、@Service、@Controller 註解,並確保該包已啓用 classpath 掃描
我們還會檢查 Spring 是否實際拾取配置文件或類,並將其加載到主上下文中。
3. 原因:org.springframework.beans.factory.NoUniqueBeanDefinitionException
另一個導致 Bean 創建異常的原因是 Spring 嘗試通過接口注入 Bean,並發現上下文中實現了同一個接口的 兩個或多個 Bean。
例如,BeanB1 和 BeanB2 都實現了相同的接口:
@Component
public class BeanB1 implements IBeanB { ... }
@Component
public class BeanB2 implements IBeanB { ... }
@Component
public class BeanA {
@Autowired
private IBeanB dependency;
...
}這將會導致 Spring Bean 工廠拋出以下異常:
Error creating bean with name 'beanA': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.baeldung.web.IBeanB com.baeldung.web.BeanA.b;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type [com.baeldung.web.IBeanB] is defined:
expected single matching bean but found 2: beanB1,beanB24. 根本原因:org.springframework.beans.BeanInstantiationException
4.1. 自定義異常
接下來是拋出異常的 Bean。在 Bean 的創建過程中拋出異常是一個簡化示例,可以幫助您更容易地理解這個問題:在 Bean 的構造函數中拋出異常。
@Component
public class BeanA {
public BeanA() {
super();
throw new NullPointerException();
}
...
}正如預期的那樣,這會導致 Spring 快速失敗,並拋出以下異常:
Error creating bean with name 'beanA' defined in file [...BeanA.class]:
Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.baeldung.web.BeanA]:
Constructor threw exception;
nested exception is java.lang.NullPointerException4.2. <em lang="en">java.lang.InstantiationException</em>
另一個可能發生的場景是,在XML中定義抽象類作為Bean。由於無法在Java的<em lang="en">@Configuration</em>文件中執行此操作,並且類路徑掃描將忽略抽象類,因此必須在XML中進行。
@Component
public abstract class BeanA implements IBeanA { ... }這是 Bean 的 XML 定義:
<bean id="beanA" class="com.baeldung.web.BeanA" />這個配置將會導致類似的異常:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'beanA' defined in class path resource [beansInXml.xml]:
Instantiation of bean failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.baeldung.web.BeanA]:
Is it an abstract class?;
nested exception is java.lang.InstantiationException4.3. `java.lang.NoSuchMethodException
如果 Bean 沒有默認構造函數,Spring 在嘗試通過查找該構造函數實例化 Bean 時,將會導致運行時異常:
@Component
public class BeanA implements IBeanA {
public BeanA(final String name) {
super();
System.out.println(name);
}
}當 classpath 掃描機制拾取這個 Bean 時,將會發生以下錯誤:
Error creating bean with name 'beanA' defined in file [...BeanA.class]: Instantiation of bean failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.baeldung.web.BeanA]:
No default constructor found;
nested exception is java.lang.NoSuchMethodException: com.baeldung.web.BeanA.<init>()當 classpath 上 Spring 依賴項的版本不一致時,可能會發生類似的異常,但診斷起來更困難。這種版本不兼容性可能導致 NoSuchMethodException,因為 API 發生了更改。解決此類問題的方法是確保項目中的所有 Spring 庫都具有完全相同的版本。
5. 原因:org.springframework.beans.NotWritablePropertyException
另一種可能性是定義一個 Bean,BeanA,並引用另一個 Bean,BeanB,而無需在 BeanA 中定義相應的 setter 方法:
@Component
public class BeanA {
private IBeanB dependency;
...
}
@Component
public class BeanB implements IBeanB { ... }以下是 Spring XML 配置:
<bean id="beanA" class="com.baeldung.web.BeanA">
<property name="beanB" ref="beanB" />
</bean>再次強調,這隻能在XML配置中發生,因為當使用Java的@Configuration</em/>註解時,編譯器會使此問題無法重現。
當然,為了解決此問題,我們需要為IBeanB</em/>添加setter方法。
@Component
public class BeanA {
private IBeanB dependency;
public void setDependency(final IBeanB dependency) {
this.dependency = dependency;
}
}6. 原因:org.springframework.beans.factory.CannotLoadBeanClassException
Spring 在無法加載定義 Bean 的類時會拋出此異常。這可能發生在 Spring XML 配置中包含一個沒有相應類定義的 Bean。例如,如果類 BeanZ 不存在,以下定義將導致異常:
<bean id="beanZ" class="com.baeldung.web.BeanZ" />根本原因是 ClassNotFoundException 以及該情況下的完整異常:
nested exception is org.springframework.beans.factory.BeanCreationException:
...
nested exception is org.springframework.beans.factory.CannotLoadBeanClassException:
Cannot find class [com.baeldung.web.BeanZ] for bean with name 'beanZ'
defined in class path resource [beansInXml.xml];
nested exception is java.lang.ClassNotFoundException: com.baeldung.web.BeanZ7. BeanCreationException 的子類
7.1. <em>org.springframework.beans.factory.BeanCurrentlyInCreationException</em>
<em>BeanCurrentlyInCreationException</em> 是 <em>BeanCreationException</em> 的一個子類。它通常在使用了構造器注入時發生,例如在存在循環依賴的情況下:
@Component
public class BeanA implements IBeanA {
private IBeanB beanB;
@Autowired
public BeanA(final IBeanB beanB) {
super();
this.beanB = beanB;
}
}
@Component
public class BeanB implements IBeanB {
final IBeanA beanA;
@Autowired
public BeanB(final IBeanA beanA) {
super();
this.beanA = beanA;
}
}Spring 將無法解決這種類型的 Wiring 場景,最終結果將是:
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'beanA':
Requested bean is currently in creation: Is there an unresolvable circular reference?異常信息非常冗長:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'beanA' defined in file [...BeanA.class]:
Unsatisfied dependency expressed through constructor argument with index 0
of type [com.baeldung.web.IBeanB]: :
Error creating bean with name 'beanB' defined in file [...BeanB.class]:
Unsatisfied dependency expressed through constructor argument with index 0
of type [com.baeldung.web.IBeanA]: :
Error creating bean with name 'beanA': Requested bean is currently in creation:
Is there an unresolvable circular reference?;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'beanA':
Requested bean is currently in creation:
Is there an unresolvable circular reference?;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'beanB' defined in file [...BeanB.class]:
Unsatisfied dependency expressed through constructor argument with index 0
of type [com.baeldung.web.IBeanA]: :
Error creating bean with name 'beanA':
Requested bean is currently in creation:
Is there an unresolvable circular reference?;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'beanA':
Requested bean is currently in creation: Is there an unresolvable circular reference?7.2. `org.springframework.beans.factory.BeanIsAbstractException
當 Bean 工廠嘗試檢索並實例化一個聲明為抽象的 Bean 時,可能會拋出此實例化異常。
public abstract class BeanA implements IBeanA {
...
}我們將其在XML配置中聲明為:
<bean id="beanA" abstract="true" class="com.baeldung.web.BeanA" />如果我們嘗試通過名稱從 Spring Context 中檢索BeanA,例如在實例化另一個 Bean 時:
@Configuration
public class Config {
@Autowired
BeanFactory beanFactory;
@Bean
public BeanB beanB() {
beanFactory.getBean("beanA");
return new BeanB();
}
}這將導致以下異常:
org.springframework.beans.factory.BeanIsAbstractException:
Error creating bean with name 'beanA': Bean definition is abstract以下是完整的異常堆棧跟蹤:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'beanB' defined in class path resource
[org/baeldung/spring/config/WebConfig.class]: Instantiation of bean failed;
nested exception is org.springframework.beans.factory.BeanDefinitionStoreException:
Factory method
[public com.baeldung.web.BeanB com.baeldung.spring.config.WebConfig.beanB()] threw exception;
nested exception is org.springframework.beans.factory.BeanIsAbstractException:
Error creating bean with name 'beanA': Bean definition is abstract8. 結論
在本文中,我們學習瞭如何導航可能導致 Spring 中 BeanCreationException 的各種原因和問題,並掌握瞭如何解決這些問題。