Spring NoSuchBeanDefinitionException – Spring的NoSuchBeanDefinitionException

最后修改: 2013年 7月 5日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we discuss the Spring org.springframework.beans.factory.NoSuchBeanDefinitionException.

在本教程中,我们将讨论Spring org.springframework.beans.factory.NoSuchBeanDefinitionException

This is a common exception thrown by the BeanFactory when trying to resolve a bean that simply isn’t defined in the Spring Context.

这是BeanFactory在试图解析Spring Context中根本没有定义的Bean时抛出的一个常见异常。

We’ll illustrate the possible causes for this problem and the available solutions.

我们将说明这个问题的可能原因和可用的解决方案。

And of course, exceptions happen when we least expect them, so have a look at the full list of exceptions and solutions in Spring.

当然,异常也会在我们最不期望的时候发生,所以请看看Spring中的全部异常列表和解决方案

2. Cause: No Qualifying Bean of Type […] Found for Dependency

2.原因 没有为依赖关系找到[…]类型的合格Bean

The most common cause of this exception is simply trying to inject a bean that isn’t defined.

导致这种异常的最常见原因是试图注入一个没有定义的Bean。

For example, BeanB is wiring in a collaborator, BeanA:

例如,BeanB在一个合作者BeanA中布线。

@Component
public class BeanA {

    @Autowired
    private BeanB dependency;
    //...
}

Now if the dependency BeanB is not defined in the Spring Context, the bootstrap process will fail with the no such bean definition exception:

现在,如果依赖关系BeanB没有在Spring Context中定义,bootstrap过程将以无此类Bean定义异常而失败。

org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type [com.baeldung.packageB.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)}

The reason is clearly indicated by Spring: expected at least 1 bean which qualifies as autowire candidate for this dependency.

Spring明确指出了原因。预计至少有1个Bean有资格成为此依赖关系的autowire候选人

One reason BeanB may not exist in the context — if beans are picked up automatically by classpath scanning, and if BeanB is correctly annotated as a bean (@Component, @Repository, @Service, @Controller, etc.) — is that it may be defined in a package that is not scanned by Spring:

一个原因是BeanB可能不存在于上下文中–如果Bean被classpath扫描自动拾取,并且BeanB被正确注释为一个Bean(@Component, @Repository, @Service, @Controller,等等。)–是指它可能被定义在一个不被Spring扫描的包中

package com.baeldung.packageB;
@Component
public class BeanB { ...}

And the classpath scanning may be configured as follows:

而classpath扫描可以按以下方式进行配置。

@Configuration
@ComponentScan("com.baeldung.packageA")
public class ContextWithJavaConfig {
    ...
}

If beans are not automatically scanned but instead defined manually, then BeanB is simply not defined in the current Spring Context.

如果Bean不是自动扫描的,而是手动定义的,那么BeanB在当前的Spring Context中根本没有定义。

3. Cause: Field […] in […] Required a Bean of Type […] That Could Not Be Found

3.原因 在[…]中的[…]字段需要一个无法找到的[…]类型的Bean

In a Spring Boot application for the above scenario, we get a different message.

在上述场景的Spring Boot应用程序中,我们得到了一个不同的消息。

Let’s take the same example where BeanB is wired in BeanA, but it’s not defined:

让我们举一个同样的例子,BeanBBeanA中被连接,但它没有被定义。

@Component
public class BeanA {
	
    @Autowired
    private BeanB dependency;
    //...
}

If we try to run this simple application, that tries to load BeanA:

如果我们尝试运行这个简单的应用程序,它试图加载BeanA

@SpringBootApplication
public class NoSuchBeanDefinitionDemoApp {

    public static void main(String[] args) {
        SpringApplication.run(NoSuchBeanDefinitionDemoApp.class, args);
    }
}

The application will fail to start with this error message:

该应用程序将无法启动,并出现该错误信息。

***************************
APPLICATION FAILED TO START
***************************

Description:

Field dependency in com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanA required a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' that could not be found.


Action:

Consider defining a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' in your configuration.

Here com.baeldung.springbootmvc.nosuchbeandefinitionexception is the package for BeanA, BeanB and NoSuchBeanDefinitionDemoApp.

这里com.baeldung.springbootmvc.nosuchbeandefinitionexceptionBeanABeanBNoSuchBeanDefinitionDemoApp的包。

The snippet for this example can be found in this GitHub project.

这个例子的片段可以在这个GitHub项目中找到。

4. Cause: No Qualifying Bean of Type […] Is Defined

4.原因 没有定义[…]类型的合格Bean

Another cause for the exception is the existence of two bean definitions in the context, instead of one.

导致该异常的另一个原因是上下文中存在两个Bean定义,而不是一个。

Let’s say an interface IBeanB is implemented by two beans, BeanB1 and BeanB2:

假设一个接口IBeanB是由两个Bean实现的,BeanB1BeanB2

@Component
public class BeanB1 implements IBeanB {
    //
}
@Component
public class BeanB2 implements IBeanB {
    //
}

Now if BeanA autowires this interface, Spring will not know which one of the two implementations to inject:

现在,如果BeanA自动连接这个接口,Spring将不知道要注入两个实现中的哪一个。

@Component
public class BeanA {

    @Autowired
    private IBeanB dependency;
    ...
}

And again, this will result in a NoSuchBeanDefinitionException being thrown by the BeanFactory:

同样,这将导致NoSuchBeanDefinitionExceptionBeanFactory抛出。

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
No qualifying bean of type 
  [com.baeldung.packageB.IBeanB] is defined: 
expected single matching bean but found 2: beanB1,beanB2

Similarly, Spring clearly indicates the reason for the wiring failure: expected single matching bean but found 2.

同样地,Spring明确指出了布线失败的原因。预期只有一个匹配的bean,但发现有两个

However, notice that in this case the exact exception being thrown is not NoSuchBeanDefinitionException but a subclass: the NoUniqueBeanDefinitionException. This new exception was introduced in Spring 3.2.1 for exactly this reason — to differentiate between the cause where no bean definition was found and where several definitions are found in the context.

然而,注意到在这种情况下,被抛出的确切异常不是NoSuchBeanDefinitionException而是一个子类。NoUniqueBeanDefinitionException.这个新的异常是在Spring 3.2.1中引入的,正是出于这个原因–区分没有找到Bean定义和在上下文中发现几个定义的原因。

Before this change, this was the above exception:

在这一变化之前,这就是上述的例外。

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type [com.baeldung.packageB.IBeanB] is defined: 
expected single matching bean but found 2: beanB1,beanB2

One solution to this problem is to use the @Qualifier annotation to specify exactly the name of the bean we want to wire:

这个问题的一个解决方案是使用@Qualifier注解来准确指定我们想要连接的bean的名称。

@Component
public class BeanA {

    @Autowired
    @Qualifier("beanB2")
    private IBeanB dependency;
    ...
}

Now Spring has enough information to make the decision of which bean to inject — BeanB1 or BeanB2 (the default name of BeanB2 is beanB2).

现在Spring有足够的信息来决定注入哪个Bean–BeanB1BeanB2BeanB2的默认名称为beanB2)。

5. Cause: No Bean Named […] Is Defined

5.原因 没有名为[…]的Bean被定义

A NoSuchBeanDefinitionException may also be thrown when a bean that isn’t defined is requested by name from the Spring context:

当一个未定义的Bean被按名称从Spring上下文请求时,也可能抛出NoSuchBeanDefinitionException

@Component
public class BeanA implements InitializingBean {

    @Autowired
    private ApplicationContext context;

    @Override
    public void afterPropertiesSet() {
        context.getBean("someBeanName");
    }
}

In this case, there is no bean definition for “someBeanName”, leading to the following exception:

在这种情况下,没有 “someBeanName “的Bean定义,导致了以下的异常。

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No bean named 'someBeanName' is defined

Again, Spring clearly and concisely indicates the reason for the failure: No bean named X is defined.

同样地,Spring清楚而简洁地指出了失败的原因。没有定义名为X的bean

6. Cause: Proxied Beans

6.原因 代理的Bean

When a bean in the context is proxied using the JDK Dynamic Proxy mechanism, the proxy will not extend the target bean (but it will implement the same interfaces).

当上下文中的Bean使用JDK动态代理机制被代理时,代理将不扩展目标Bean(但它将实现相同的接口)。

Because of this, if the bean is injected by an interface, it will be correctly wired in. However, if the bean is injected by the actual class, Spring will not find a bean definition that matches the class since the proxy does not actually extend the class.

正因为如此,如果Bean是由一个接口注入的,它将被正确地连接进来。然而,如果Bean是由实际的类注入的,Spring将不会找到与该类相匹配的Bean定义,因为代理实际上并没有扩展该类。

A very common reason the bean may be proxied is the Spring transactional support, namely beans that are annotated with @Transactional.

一个很常见的原因是,Bean可能被代理了,那就是Spring事务性支持,即用@Transactional注释的Bean。

For example, if ServiceA injects ServiceB, and both services are transactional, injecting by the class definition will not work:

例如,如果ServiceA注入ServiceB,并且这两个服务都是事务性的,那么通过类定义注入将不起作用。

@Service
@Transactional
public class ServiceA implements IServiceA{

    @Autowired
    private ServiceB serviceB;
    ...
}

@Service
@Transactional
public class ServiceB implements IServiceB{
    ...
}

The same two services, this time correctly injecting by the interface, will be okay:

同样的两个服务,这次正确地通过接口注入,就可以了。

@Service
@Transactional
public class ServiceA implements IServiceA{

    @Autowired
    private IServiceB serviceB;
    ...
}

@Service
@Transactional
public class ServiceB implements IServiceB{
    ...
}

7. Conclusion

7.结论

This article discussed examples of the possible causes for the common NoSuchBeanDefinitionException — with a focus on how to address these exceptions in practice.

本文讨论了常见的NoSuchBeanDefinitionException的可能原因的例子–重点是如何在实践中解决这些异常。

The implementation of all these exceptions examples can be found in the GitHub project. This is an Eclipse-based project, so it should be easy to import and run as it is.

所有这些例外的实现都可以在GitHub项目中找到。这是一个基于Eclipse的项目,所以应该很容易导入并按原样运行。

Finally, the full list of exceptions and solutions in Spring might be a good resource to bookmark.

最后,Spring中完整的异常列表和解决方案可能是一个不错的资源,可以收藏。