Spring BeanCreationException

2023/05/13

1. 概述

在本教程中,我们将讨论Spring org.springframework.beans.factory.BeanCreationException。当BeanFactory创建bean定义的bean并遇到问题时抛出一个非常常见的异常。本文将探讨此异常的最常见原因以及解决方案。

延伸阅读

Spring的控制反转和依赖注入简介

快速介绍控制反转和依赖注入的概念,然后使用Spring框架进行简单演示

阅读更多

Spring中的BeanNameAware和BeanFactoryAware接口

查看在Spring中使用BeanNameAware和BeanFactoryAware接口。

阅读更多

Spring 5函数Bean注册

查看如何使用Spring 5中的函数式方法注册bean。

阅读更多

2. 原因:org.springframework.beans.factory.NoSuchBeanDefinitionException

到目前为止,BeanCreationException最常见的原因是Spring试图注入上下文中不存在的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 cn.tuyucheng.taketoday.web.BeanB cpm.baeldung.web.BeanA.dependency; 
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type [cn.tuyucheng.taketoday.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类中
  • 或者用@Component、@Repository、@Service、@Controller注解,并且类路径扫描对该包是活动的

我们还将检查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 cn.tuyucheng.taketoday.web.IBeanB cn.tuyucheng.taketoday.web.BeanA.b; 
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
No qualifying bean of type [cn.tuyucheng.taketoday.web.IBeanB] is defined: 
expected single matching bean but found 2: beanB1,beanB2

4. 原因:org.springframework.beans.BeanInstantiationException

4.1 自定义异常

接下来是一个在其创建过程中抛出异常的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 [cn.tuyucheng.taketoday.web.BeanA]: 
Constructor threw exception; 
nested exception is java.lang.NullPointerException

4.2 java.lang.InstantiationException异常

BeanInstantiationException的另一种可能出现是将抽象类定义为XML中的bean;这必须在XML中,因为在Java@Configuration文件中无法做到这一点,类路径扫描将忽略抽象类:

@Component
public abstract class BeanA implements IBeanA { ... }

这是bean的XML定义:

<bean id="beanA" class="cn.tuyucheng.taketoday.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 [cn.tuyucheng.taketoday.web.BeanA]: 
Is it an abstract class?; 
nested exception is java.lang.InstantiationException

4.3 java.lang.NoSuchMethodException异常

如果bean没有默认构造函数,而Spring试图通过查找该构造函数来实例化它,这将导致运行时异常:

@Component
public class BeanA implements IBeanA {

    public BeanA(final String name) {
        super();
        System.out.println(name);
    }
}

当类路径扫描机制拾取这个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 [cn.tuyucheng.taketoday.web.BeanA]: 
No default constructor found; 
nested exception is java.lang.NoSuchMethodException: cn.tuyucheng.taketoday.web.BeanA.<init>()

当类路径上的Spring依赖项没有相同的版本时,可能会发生类似的异常,但更难诊断。由于API更改,这种版本不兼容可能会导致NoSuchMethodException。解决此类问题的方法是确保所有Spring库在项目中具有完全相同的版本。

5. 原因:org.springframework.beans.NotWritablePropertyException

另一种可能性是定义一个beanBeanA,并引用另一个beanBeanB,而BeanA中没有相应的setter方法:

@Component
public class BeanA {
    private IBeanB dependency;
    ...
}
@Component
public class BeanB implements IBeanB { ... }

这是SpringXML配置:

<bean id="beanA" class="cn.tuyucheng.taketoday.web.BeanA">
    <property name="beanB" ref="beanB" />
</bean>

同样,这只会发生在XML配置中,因为在使用Java@Configuration时,编译器将无法重现此问题。

当然,为了解决这个问题,我们需要为IBeanB添加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的类时抛出此异常。如果SpringXML配置包含一个根本没有对应类的bean,则可能会发生这种情况。例如,如果类BeanZ不存在,则以下定义将导致异常:

<bean id="beanZ" class="cn.tuyucheng.taketoday.web.BeanZ" />

ClassNotFoundException的根本原因和本例中的完整异常是:

nested exception is org.springframework.beans.factory.BeanCreationException: 
...
nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: 
Cannot find class [cn.tuyucheng.taketoday.web.BeanZ] for bean with name 'beanZ' 
defined in class path resource [beansInXml.xml]; 
nested exception is java.lang.ClassNotFoundException: cn.tuyucheng.taketoday.web.BeanZ

7. BeanCreationException的孩子

7.1 org.springframework.beans.factory.BeanCurrentlyInCreationException_

BeanCreationException的子类之一是BeanCurrentlyInCreationException。这通常发生在使用构造函数注入时,例如,在循环依赖的情况下:

@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无法解决这种布线场景,最终结果将是:

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 [cn.tuyucheng.taketoday.web.IBeanB]: : 
Error creating bean with name 'beanB' defined in file [...BeanB.class]: 
Unsatisfied dependency expressed through constructor argument with index 0 
of type [cn.tuyucheng.taketoday.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 [cn.tuyucheng.taketoday.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

当BeanFactory试图检索和实例化一个声明为抽象的bean时,可能会发生此实例化异常:

public abstract class BeanA implements IBeanA {
   // ...
}

我们在XML配置中将其声明为:

<bean id="beanA" abstract="true" class="cn.tuyucheng.taketoday.web.BeanA" />

如果我们尝试通过名称从Spring上下文中检索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 cn.tuyucheng.taketoday.web.BeanB cn.tuyucheng.taketoday.spring.config.WebConfig.beanB()] threw exception; 
nested exception is org.springframework.beans.factory.BeanIsAbstractException: 
Error creating bean with name 'beanA': Bean definition is abstract

8. 总结

在本文中,我们了解了如何解决可能导致Spring中的BeanCreationException的各种原因和问题,并很好地掌握了如何解决所有这些问题。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章