概述

org.springframework.beans.factory.NoSuchBeanDefinitionException 是很常见的异常,可以说绝大多数使用过 Spring 的人都曾遇到过它。本文旨在总结下NoSuchBeanDefinitionException(以下简称 NSBDE)的含义,哪些情况下可能抛出 NSBDE,和如何解决(文中配置均用 JavaConfig)。

什么是 NoSuchBeanDefinitionException

从字面其实就很好理解,NoSuchBeanDefinitionException 就是没有找到指定 Bean 的 Definition。NoSuchBeanDefinitionException 的 JavaDoc是这样定义的:

Exception thrown when a BeanFactory is asked for a bean instance for which it cannot find a definition. This may point to a non-existing bean, a non-unique bean, or a manually registered singleton instance without an associated bean definition.

下面看看可能抛出 NSBDE 的一些情况。

情况1: No qualifying bean of type […] found for dependency

最常见的抛出 NSBDE 的情况就是在一个 BeanA 中注入 BeanB 时找不到 BeanB 的定义。例子如下:

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

当在 BeanA 中注入 BeanB 时,如果在 Spring 上下文中找不到 BeanB 的定义,就会抛出 NSBDE。异常信息如下:

org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [org.baeldung.packageB.BeanB]found for dependency: expected at least 1 bean which qualifies asautowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

抛异常的原因在异常信息中说的很清楚:expected at least 1 bean which qualifies as autowire candidate for this dependency。所以要么是 BeanB 不存在在 Spring 上下文中(比如没有标注 @ Component,@Repository,@Service, @Controller等注解) ,要么就是 BeanB 所在的包没有被 Spring 扫描到。

解决办法就是先确认 BeanB 有没有被某些注解声明为 Bean:

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

如果 BeanB 已经被声明为一个 Bean,就再确认 BeanB 所在的包有没有被扫描。

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

情况2: No qualifying bean of type […] is defined

还有一种可能抛出 NSBDE 的情况是在上下文中存在着两个 Bean,比如有一个接口 IBeanB,它有两个实现类 BeanB1 和 BeanB2。

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

现在,如果 BeanA 按照下面的方式注入,那么 Spring 将不知道要注入两个实现中的哪一个,就会抛出 NSBDE。

@Component
public class BeanA {@Autowiredprivate IBeanB dependency;
}

异常信息如下:

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

仔细看异常信息会发现,并不是直接抛出 NSBDE,而是它的子类 NoUniqueBeanDefinitionException,这是 Spring 3.2.1 之后引入的新异常,目的就是为了和第一种找不到 Bean Definition 的情况作区分。

解决办法1就是利用 @Qualifier 注解,明确指定要注入的 Bean 的名字(BeanB2 默认的名字就是 beanB2)。

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

除了指定名字,我们还可以将其中一个 Bean 加上 @Primary的注解,这样会选择加了 Primary 注解的 Bean 来注入,而不会抛异常:

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

这样 Spring 就能够知道到底应该注入哪个 Bean 了。

情况3: No Bean Named […] is defined

NSBDE 还可能在从 Spring 上下文中通过名字获取一个 Bean 时抛出。

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

在这种情况中,如果找不到指定名字 Bean 的 Definition,就会抛出如下异常:

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

情况4: 代理 Beans

Spring 通过 AOP 代理 实现了许多高级功能,比如:

  • 通过 @Transactional完成 事务管理
  • 通过 @Cacheable实现缓存
  • 通过 @Async和 @Scheduled实现任务调度和异步执行

Spring 有两种方式实现代理:

  1. 利用 JDK 动态代理机制 ,在运行时为实现了某些接口的类动态创建一个实现了同样接口的代理对象。
  2. 使用 CGLIB,CGLIB 可以在运行期扩展Java类与实现Java接口,也就是说当一个类没有实现接口时,必须用 CGLIB 生成代理对象。

所以,当 Spring 上下文中的一个实现了某个接口的 Bean 通过JDK 动态代理机制被代理时,代理类并不是继承了目标类,而是实现同样的接口。

也正因为如此,如果一个 Bean 通过接口注入时,可以成功被注入。但如果是通过真正的类注入,那么 Spring 将无法找到匹配这个类的 Definition——因为代理类并没有继承这个类。

以 Spring 中比较常见的事务管理为例,假设 ServiceA 中要注入 ServiceB,两个 Service 均标注了 @Transactional注解来进行事务管理,那么下面的注入方式是不会正常 work 的。

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

解决办法就是通过接口来进行注入:

@Service
@Transactional
public class ServiceA implements IServiceA{@Autowiredprivate IServiceB serviceB;}@Service
@Transactional
public class ServiceB implements IServiceB{}


原作者:Giraffe
原文链接:谈谈 NoSuchBeanDefinitionException
原出处:个人博客
侵删

谈谈 Spring 中的 NoSuchBeanDefinitionException相关推荐

  1. 谈谈spring中的拦截器interceptor

    谈谈spring中的拦截器 在web开发中,拦截器是经常用到的功能.它可以帮我们验证是否登陆.预先设置数据以及统计方法的执行效率等等.今天就来详细的谈一下spring中的拦截器.spring中拦截器主 ...

  2. 谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗?

    本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 推荐阅读: Spring官网阅读 | 总结篇 Spring杂 ...

  3. 谈谈Spring中的IOC和AOP概念 - 倪升武的博客 - CSDN博客

    转载于https://blog.csdn.net/eson_15/article/details/51090040 IOC和AOP是Spring中的两个核心的概念,下面谈谈对这两个概念的理解. 1. ...

  4. 谈谈Spring中的IOC、DI和AOP概念

    看了大神的解释感觉受益匪浅,所以就将其保存,方便自己看,并最后总结出自己的理解 1. IOC(Inverse of Control):控制反转,也可以称为依赖倒置. 所谓依赖,从程序的角度看,就是比如 ...

  5. ajax redirectattributes 使用,Spring中RedirectAttributes对象重定向传参

    Spring3中的FlashAttribute 为 了防止用户刷新重复提交,save操作之后一般会redirect到另一个页面,同时带点操作成功的提示信息.因为是Redirect,Request里 的 ...

  6. 这篇文章,我们来谈一谈Spring中的属性注入

    本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring中的对象跟Bean,你知道Spring怎么创 ...

  7. 面试必杀技,讲一讲Spring中的循环依赖

    本系列文章: 听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configu ...

  8. 谈谈自己对Spring中IOC和AOP的理解

    Spring框架的核心思想主要是IOC和AOP的思想 IOC IOC概念 Spring中的IOC AOP AOP概念 百度百科的解释 个人理解 AOP思想 IOC IOC概念 所谓IOC即 Inver ...

  9. (转)Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别

    Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...

最新文章

  1. 自然语言交流系统 phxnet团队 创新实训 个人博客 (二)
  2. latex 特殊符号
  3. SAP CRM Fiori busy dialog的工作原理
  4. sketch钢笔工具_Sketch和Figma,不同的工具等于不同的结果
  5. 操作系统(二): 进程与线程
  6. 万字详解Docker架构原理、功能及使用
  7. 机器视觉打光方案(纽扣电池胶纸)
  8. 【语音分离】基于matlab FASTICA语音分离【含Matlab源码 1023期】
  9. 如何在通达信中展现漂亮的港资持股曲线
  10. 维纳滤波和卡尔曼滤波
  11. lua脚本java_java操作lua脚本
  12. 百鸡百钱问题和( 30人消费50元,可能包括男人女人小孩,男人3元,女人2元,小孩1元,问各有多少人)问题
  13. 使用Certbot配置SSL证书【ubuntu系统】
  14. 什么是百度SEO?百度SEO优化怎么做?
  15. 看一个师兄的操作系统视频有感
  16. python设置刻度间隔不等_Matplotlib绘图遇到时间刻度就犯难?现在,一次性告诉你四种方法...
  17. 华为鸿蒙harmonyos面相全场,关于华为:HDC2020华为鸿蒙HarmonyOS会带来哪些不一样的体验...
  18. 我奋斗了18年才和你坐在一起喝咖啡与我奋斗了18年不是为了和你一起喝咖啡
  19. wpsoffice安卓历史版本_WPS Office
  20. 合肥工业大学2021离散数学上机实验一

热门文章

  1. vue封装自定义数字键盘组件
  2. 与ck读音相同的单词有哪些
  3. 怎么把exe转成手机的可执行文件
  4. 五行代码实现MD5加密(超级简单,一看就会)
  5. YOLOv3 代码详解(2) —— 数据处理 dataset.py解析:输入图片增强、制作模型的每层输出的标签
  6. 电子榨菜之Mendix漫画
  7. 你一定要这么多功能么?——献给希望创业的兄弟们
  8. CS(反恐精英)奥林匹克运动会
  9. 美国签证经历(完善中)
  10. “测试之道”主题(深圳站)