前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >不畏浮云遮望眼:望断`NoSuchBeanDefinitionException`

不畏浮云遮望眼:望断`NoSuchBeanDefinitionException`

作者头像
烟雨平生
发布2023-03-07 14:51:54
5410
发布2023-03-07 14:51:54
举报
文章被收录于专栏:数字化之路数字化之路
云南.丽江

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

作者:Eugen Paraschiv

译者:helloworldtang

1.概览

在本文中,我们将讨论Spring中的org.springframework.beans.factory.NoSuchBeanDefinitionException异常——当BeanFactory试图装配一个在Spring上下文中没有定义的 Bean时,自动装配会失败并抛出这个异常。

我们将找出导致这个异常的可能原因并给出可用的解决方案。

当然,异常总是在你最不希望看到的时候发生;Spring异常及解决方案的完整列表可以在这里查看。

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

这个异常最常见的原因是试图注入一个未定义的 Bean。例如,在* BeanB中自动装配了BeanA*:

代码语言:javascript
复制
@Component
public class BeanA {

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

现在,如果在Spring上下文中没有定义这个依赖项BeanB,那么将启动失败,并抛出这个异常NoSuchBeanDefinitionException

代码语言:javascript
复制
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)}

Spring已经将错误原因提示地很明显了: “expected at least 1 bean which qualifies as autowire candidate for this dependency“

原因是BeanB 在Spring上下文中不存在——如果 Bean实例化是通过扫描指定的package,并且如果BeanB已经被正确地标注为一个 Bean(添加过了@Component或@Repository或@Service或@Controller等其它基于元注解@Component的业务注解)——也就是说这个类所在的package没有被Spring扫描到

代码语言:javascript
复制
package org.baeldung.packageB;
@Component
public class BeanB { 
    ...
}

与这对应的, @ComponentScan的配置情况如下所示:

代码语言:javascript
复制
@Configuration
@ComponentScan("org.baeldung.packageA")
public class ContextWithJavaConfig {
    ...
}

如果 Bean手动初始化而不是通过Spring的自动扫描,那么在当前的Spring上下文中是不存在BeanB的。

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

在上述场景中,如果是一个Spring Boot应用程序,我们将得到一个不同的报错消息。

示例如下,其中BeanB被自动装配到BeanA,但是BeanB并没有被定义:

代码语言:javascript
复制
@Component
public class BeanA {

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

如果我们试图运行这个需要加载BeanA的简单应用程序:

代码语言:javascript
复制
@SpringBootApplication
public class NoSuchBeanDefinitionDemoApp {

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

这个应用程序将启动失败,并报如下错误:

代码语言:javascript
复制
***************************
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.

在这里, com.baeldung.springbootmvc.nosuchbeandefinitionexception是BeanA、BeanB和NoSuchBeanDefinitionDemoApp的package。

这个示例的完整代码可以在这个Github项目中找到。

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

异常的另一个原因是Spring上下文中存在两个 Bean定义,而不是一个。例如,如果一个接口IBeanB有两个 Bean实现——BeanB1和BeanB2:

代码语言:javascript
复制
@Component
public class BeanB1 implements IBeanB {
    //
}
@Component
public class BeanB2 implements IBeanB {
    //
}

现在,如果在BeanA中自动装配了这个接口,那么Spring将不知道使用这两个实现中的哪一个来进行注入:

代码语言:javascript
复制
@Component
public class BeanA {

    @Autowired
    private IBeanB dependency;
    ...
}

同样,这将导致BeanFactory抛出异常 NoSuchBeanDefinitionException

代码语言:javascript
复制
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也清楚地指出了装配失败的原因:“expected single matching bean but found 2”。

但是,请注意,在这种情况下,抛出的异常不是NoSuchBeanDefinitionException,而是它的一个子类–NoUniqueBeanDefinitionException。这个新异常在Spring 3.2.1时就已经引入的,它的引入就是为了区分在Spring上下文中没有找到 Bean定义和找到多个定义。

在没有引入NoUniqueBeanDefinitionException之前,会抛出这样的异常:

代码语言:javascript
复制
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名字【在Spring中,所有的东西都会赋予一个名字】:

代码语言:javascript
复制
@Component
public class BeanA {

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

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

5.Cause: No Bean Named […] is defined

当通过名字从Spring上下文中请求一个没有定义的 Bean时,也可能抛出NoSuchBeanDefinitionException异常:

代码语言:javascript
复制
@Component
public class BeanA implements InitializingBean {

    @Autowired
    private ApplicationContext context;

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

在这种情况下,由于 Bean“someBeanName”在Spring上下文中是没有定义的——这将导致抛出下面的异常:

代码语言:javascript
复制
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No bean named 'someBeanName' is defined

同样,Spring清晰又简洁地指出了失败的原因:“No bean named X is defined“。

6.Cause: Proxied Beans

请注意:如果Spring上下文中的 Bean添加了JDK动态代理特性,那么代理是不会织入到具体的实现类 Bean,即使用接口的具体实现类进行注入时,代理将失效(虽然实现类也实现了相同的接口)。

正因为如此,如果 Bean是通过一个接口注入,事务将会被正确地织入。如果 Bean是由一个实现类注入的,那么Spring将不会找到与该类相匹配的 Bean定义——即代理不会被织入。

Bean代理的一个非常常见的原因是Spring的事务支持——即用 @Transactional注解修饰的 Bean

例如,如果将ServiceB注入到ServiceA,并且这两个服务都是支持事务的,那么通过类定义注入服务的事务将不会生效:

代码语言:javascript
复制
@Service
@Transactional
public class ServiceA implements IServiceA{

    @Autowired
    private ServiceB serviceB;
    ...
}

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

在下面的示例中,因为正确地通过接口进行注入,因此,两个服务的事务都会生效:

代码语言:javascript
复制
@Service
@Transactional
public class ServiceA implements IServiceA{

    @Autowired
    private IServiceB serviceB;
    ...
}

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

7. 总结

本教程结合实例讨论了引发NoSuchBeanDefinitionException的常见原因,重点讨论了如何在实践中处理这些异常。

文中用到的示例代码都可以在GitHub项目 上找到——这是一个基于Eclipse的项目,因此应该很容易导入和运行。

最后,在Spring中,这篇完整的异常及解决方案列表 应该写得不错,建议收藏。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-10-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 的数字化之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.概览
  • 2.Cause: No qualifying bean of type […] found for dependency
  • 3.Cause: Field […] in […] required a bean of type […] that could not be found
  • 4.Cause: No qualifying bean of type […] is defined
  • 5.Cause: No Bean Named […] is defined
  • 6.Cause: Proxied Beans
  • 7. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档