Spring NoSuchBeanDefinitionException

概述

在本文中,我们将讨论spring org.springframework.beans.factory.NoSuchBeanDefinitionException——这是BeanFactory在尝试解析一个在Spring上下文中没有定义的bean时抛出的一个常见异常。

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

当然,如果产生了异常你还可以点击这里查看异常和解决方案的完整列表。

 

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

这个异常最常见的原因就是试图注入一个没有定义的bean。例如,BeanB在BeanA中注入:

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

 现在,如果在Spring上下文中没有定义依赖项BeanB,那么注入过程将失败,出现 the no such bean definition exception

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

 从报错信息可以看出:至少需要1个可以作为这个依赖项注入的Bean。


Spring会通过配置的路径或者默认路径自动扫描获取bean,如果beanB正确地做了注解(@component、@repository、@service、@controller等),beanB还是不存在于上下文中的话,那么它可能被定义在一个没有被spring扫描的包中。

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

而类路径扫描可以配置如下:

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

如果Bean不是自动扫描的,而是手动定义的,那么BeanB只是在当前的Spring上下文中没有定义。

 

2、Cause: Field […] in […] required a bean of type […] that could not be found

在上述场景的Spring启动应用程序中,我们得到了不同的消息。我们举一个同样的例子,在BeanA中注入了BeanB,但没有定义:

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

我们运行一个简单的程序,尝试在BeanA中注入BeanB

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

 这是报错信息

***************************
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.

在这里,BeanA,BeanB和NoSuchBeanDefinitionDemoApp都在com.baeldung.springbootmvc.nosuchbeandefinitionexception包下面

这段例子在GitHub上可以找到。

 

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

另一个导致异常的原因是存在不止一个Bean定义在上下文中。例如,BeanB1和BeanB2都实现IBeanB接口

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

现在,如果在BeanA中注入本接口,Spring就不知道实现哪一个接口:

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

这样BeanFactory就会报NoSuchBeanDefinitionException异常

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

同样,Spring清楚地指出了注入失败的原因:“预期匹配单个Bean,但发现了2个”。

在这种情况下,确切异常不是NoSuchBeanDefinitionException,而是一个子类the NoUniqueBeanDefinitionException。在Spring3.2.1中引入了这个新的异常,就是为了区分没有找到Bean定义的原因和在上下文中找到多个定义的原因。

在此更改之前,上述例外情况是:

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

这个问题的一个解决方案是使用@qualifier注释来精确地指定要连接的bean的名称:

@Component
public class BeanA {
 
    @Autowired
    @Qualifier("beanB2")
    private IBeanB dependency;
    ...
}

现在Spring有足够的信息来决定注入哪个Bean——BeanB1或BeanB2(BeanB2的默认名称是beanB2)。

 

4、Cause: No Bean Named […] is defined

当从Spring上下文中按名称请求未定义的Bean时,也可能引发NoSuchBeanDefinitionException:

@Component
public class BeanA implements InitializingBean {
 
    @Autowired
    private ApplicationContext context;
 
    @Override
    public void afterPropertiesSet() {
        context.getBean("someBeanName");
    }
}

在这种情况下,“somebeanname”没有bean定义–导致以下异常:

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

同样的,Spring明确的指出了错误的原因: “No bean named X is defined“.

 

5、Cause: Proxied Beans

当使用JDK动态代理机制代理上下文中的Bean时,代理对象将不会继承目标Bean(但是会实现相同的接口)。

如果Bean是由一个接口注入的,那么它就能正确的注入。但是,如果Bean是由实际类注入的,那么Spring将找不到与类匹配的Bean定义,因为代理实际上没有继承类。

Spring事务性支持是常见的Bean代理的运用,即用@transactional注释的Bean。

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

@Service
@Transactional
public class ServiceA implements IServiceA{
 
    @Autowired
    private ServiceB serviceB;
    ...
}
 
@Service
@Transactional
public class ServiceB implements IServiceB{
    ...
}

同样的两个服务,如果用接口就可以正确地注入:

@Service
@Transactional
public class ServiceA implements IServiceA{
 
    @Autowired
    private IServiceB serviceB;
    ...
}
 
@Service
@Transactional
public class ServiceB implements IServiceB{
    ...
}

 

总结

本教程讨论了常见NoSuchBeanDefinitionException的可能原因示例,重点介绍了如何在实践中解决这些异常。

所有这些异常示例的实现都可以在Github项目中找到。由于这是一个基于Eclipse的项目,可以很容易导入和运行。

最后,Spring中的异常和解决方案的完整列表是比较好的收藏资源。

 

 

原文链接:https://www.baeldung.com/spring-nosuchbeandefinitionexception

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值