谈谈 Spring 中的 NoSuchBeanDefinitionException
概述
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 有两种方式实现代理:
- 利用 JDK 动态代理机制 ,在运行时为
实现了某些接口
的类动态创建一个实现了同样接口的代理对象。 - 使用 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相关推荐
- 谈谈spring中的拦截器interceptor
谈谈spring中的拦截器 在web开发中,拦截器是经常用到的功能.它可以帮我们验证是否登陆.预先设置数据以及统计方法的执行效率等等.今天就来详细的谈一下spring中的拦截器.spring中拦截器主 ...
- 谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗?
本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 推荐阅读: Spring官网阅读 | 总结篇 Spring杂 ...
- 谈谈Spring中的IOC和AOP概念 - 倪升武的博客 - CSDN博客
转载于https://blog.csdn.net/eson_15/article/details/51090040 IOC和AOP是Spring中的两个核心的概念,下面谈谈对这两个概念的理解. 1. ...
- 谈谈Spring中的IOC、DI和AOP概念
看了大神的解释感觉受益匪浅,所以就将其保存,方便自己看,并最后总结出自己的理解 1. IOC(Inverse of Control):控制反转,也可以称为依赖倒置. 所谓依赖,从程序的角度看,就是比如 ...
- ajax redirectattributes 使用,Spring中RedirectAttributes对象重定向传参
Spring3中的FlashAttribute 为 了防止用户刷新重复提交,save操作之后一般会redirect到另一个页面,同时带点操作成功的提示信息.因为是Redirect,Request里 的 ...
- 这篇文章,我们来谈一谈Spring中的属性注入
本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring中的对象跟Bean,你知道Spring怎么创 ...
- 面试必杀技,讲一讲Spring中的循环依赖
本系列文章: 听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configu ...
- 谈谈自己对Spring中IOC和AOP的理解
Spring框架的核心思想主要是IOC和AOP的思想 IOC IOC概念 Spring中的IOC AOP AOP概念 百度百科的解释 个人理解 AOP思想 IOC IOC概念 所谓IOC即 Inver ...
- (转)Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别
Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...
最新文章
- 自然语言交流系统 phxnet团队 创新实训 个人博客 (二)
- latex 特殊符号
- SAP CRM Fiori busy dialog的工作原理
- sketch钢笔工具_Sketch和Figma,不同的工具等于不同的结果
- 操作系统(二): 进程与线程
- 万字详解Docker架构原理、功能及使用
- 机器视觉打光方案(纽扣电池胶纸)
- 【语音分离】基于matlab FASTICA语音分离【含Matlab源码 1023期】
- 如何在通达信中展现漂亮的港资持股曲线
- 维纳滤波和卡尔曼滤波
- lua脚本java_java操作lua脚本
- 百鸡百钱问题和( 30人消费50元,可能包括男人女人小孩,男人3元,女人2元,小孩1元,问各有多少人)问题
- 使用Certbot配置SSL证书【ubuntu系统】
- 什么是百度SEO?百度SEO优化怎么做?
- 看一个师兄的操作系统视频有感
- python设置刻度间隔不等_Matplotlib绘图遇到时间刻度就犯难?现在,一次性告诉你四种方法...
- 华为鸿蒙harmonyos面相全场,关于华为:HDC2020华为鸿蒙HarmonyOS会带来哪些不一样的体验...
- 我奋斗了18年才和你坐在一起喝咖啡与我奋斗了18年不是为了和你一起喝咖啡
- wpsoffice安卓历史版本_WPS Office
- 合肥工业大学2021离散数学上机实验一