1. 概述
NoSuchBeanDefinitionException 是 BeanFactory 在 Spring Context 中未找到bean定义时抛出的常见异常。
本文将解释可能导致该异常的原因和解决办法。 有关 Spring 的全部异常问题请查看这篇文章.
2. Cause: No Qualifying Bean of Type […] Found for Dependency
最常见的错误原因是因为试图注入未定义的bean。
例如,下面的 BeanA 依赖 BeanB:
@Component
public class BeanA {
@Autowired
private BeanB dependency;
//...
}
如果 BeanB 没有在 Spring Context 中定义,启动时就会报 the no such bean definition exception 异常。
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)}
检查BeanB是否被正确的注解为bean(@Component、@Repository、@Service、@Controller)。
package com.baeldung.packageB;
@Component
public class BeanB { ...}
另外可能是所在package没有被Spring扫描到。可通过@ComponentScan,手动指定扫描路径。
@Configuration
@ComponentScan("com.baeldung.packageA")
public class ContextWithJavaConfig {
...
}
3. Cause: Field […] in […] Required a Bean of Type […] That Could Not Be Found
在上面场景的Spring Boot应用程序中,我们得到了不同的消息。
让我们举一个相同的例子,其中BeanB被BeanA依赖,但它没有定义:
@Component
public class BeanA {
@Autowired
private BeanB dependency;
//...
}
运行:
@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上。
4. Cause: No Qualifying Bean of Type […] Is Defined
另一原因是因为Spring Context中存在两个相同的bean定义。
例如下面 BeanB1 和 BeanB2 都实现了 IBeanB接口:
@Component
public class BeanB1 implements IBeanB {
//
}
@Component
public class BeanB2 implements IBeanB {
//
}
现在如果 BeanA @Autowired 接口IBeanB, 但因为IBeanB有2个实现,Spring不知道应该注入那一个就会抛 NoSuchBeanDefinitionException 异常。
@Component
public class BeanA {
@Autowired
private IBeanB dependency;
...
}
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
确切的说这里抛出的是NoSuchBeanDefinitionException异常,而是其子类 - NoUniqueBeanDefinitionException。它是在Spring 3.2.1后引入的。之前版本是这样的:
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
解决办法是使用 @Qualifier 注解指定要注入的bean名称:
@Component
public class BeanA {
@Autowired
@Qualifier("beanB2")
private IBeanB dependency;
...
}
现在Spring有足够的信息来决定注入哪个bean——BeanB1或BeanB2(BeanB2的默认名称是beanB2)。
5. Cause: No Bean Named […] Is Defined
当我们通过name方式加载bean也可能导致这个异常:
@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
6. Cause: Proxied Beans
当Spring使用JDK动态代理机制创建代理时,代理实现了与目标bean相同的接口,但不继承目标bean类
因此,如果通过接口注入bean,Spring可以正确地进行注入,因为代理实现了该接口。如果通过实际类注入bean,Spring无法找到匹配的bean定义,因为代理不继承目标类。
一个非常常见的原因是由于Spring的事务支持,即那些使用@Transactional注解的bean可能会被代理。
例如,如果 ServiceA 注入了 ServiceB,并且这两个服务都是@Transactional,通过类定义进行注入将无法正常工作
@Service
@Transactional
public class ServiceA implements IServiceA{
@Autowired
private ServiceB serviceB;
...
}
@Service
@Transactional
public class ServiceB implements IServiceB{
...
}
下面通过接口注入是OK的:
@Service
@Transactional
public class ServiceA implements IServiceA{
@Autowired
private IServiceB serviceB;
...
}
@Service
@Transactional
public class ServiceB implements IServiceB{
...
}
7. 总结
本文我们讨论了导致NoSuchBeanDefinitionException异常的常见原因和解决办法,文章的代码放在GitHub 上。