请解释Spring中关于NosuchBeanDefinitionException
异常的以下内容:
这篇文章是关于使用Spring的应用程序中出现NosuchBeanDefinitionException
的全面问答。
NosuchBeanDefinitionException
的javadoc解释
当BeanFactory
被请求获取一个它找不到定义的bean实例时引发的异常。这可能指向一个不存在的bean、一个非唯一的bean,或者一个没有关联bean定义的手动注册的单例实例。
一个BeanFactory
基本上是表示Spring对控制容器的反转的抽象。它在内部和外部向应用程序公开bean。当它无法找到或检索这些bean时,它会抛出NoSuchBeanDefinitionException
。
在下面的示例中
@Configuration
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
ctx.getBean(Foo.class);
}
}
class Foo {}
我们还没有通过@bean
方法、@component
扫描、XML定义或任何其他方式注册foo
类型的bean定义。因此,由AnnotationConfigApplicationContext
管理的BeanFactory
没有指示从何处获取getBean(foo.class)
请求的bean。上面的片段抛出
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.example.Foo] is defined
类似地,在尝试满足@autowired
依赖项时可能引发了异常。例如,
@Configuration
@ComponentScan
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
}
}
@Component
class Foo { @Autowired Bar bar; }
class Bar { }
这里,通过@componentscan
为foo
注册了一个bean定义。但是Spring对bar
一无所知。因此,在尝试自动连接foo
bean实例的bar
字段时,它无法找到相应的bean。它抛出(嵌套在UnsatisfiedDependencyException
中)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.example.Bar] found for dependency [com.example.Bar]:
expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
注册bean定义有多种方法。
@configuration
类中的
@bean
方法或XML Configuration
方法
@component
(及其元注释,例如@repository
)通过@componentscan
或
xmlGenericApplicationContext#RegisterBeanDefinition
BeanDefinitionRegistryPostProcessor
...还有更多。
确保您期望的bean正确注册。
一个常见的错误是多次注册bean,即。为同一类型混合上面的选项。例如,我可能
@Component
public class Foo {}
<context:component-scan base-packages="com.example" />
<bean name="eg-different-name" class="com.example.Foo />
<import resource=""/>
而Java则提供@importresource
注释。
有些时候,您需要为同一类型(或接口)提供多个bean。例如,您的应用程序可能使用两个数据库,一个MySQL实例和一个Oracle实例。在这种情况下,您将有两个datasource
bean来管理与每个bean的连接。对于(简化的)示例,如下所示
@Configuration
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
System.out.println(ctx.getBean(DataSource.class));
}
@Bean(name = "mysql")
public DataSource mysql() { return new MySQL(); }
@Bean(name = "oracle")
public DataSource oracle() { return new Oracle(); }
}
interface DataSource{}
class MySQL implements DataSource {}
class Oracle implements DataSource {}
投掷
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type [com.example.DataSource] is defined:
expected single matching bean but found 2: oracle,mysql
@Bean(name = "mysql")
@Primary
public DataSource mysql() { return new MySQL(); }
前面的代码段不会抛出异常,而是返回mysql
bean。
您还可以使用@qualifier
(及其XML中的等价物)对bean选择过程进行更多的控制,如文档中所述。虽然@autowired
主要用于按类型自动连接,但@qualifier
允许按名称自动连接。例如,
@Bean(name = "mysql")
@Qualifier(value = "main")
public DataSource mysql() { return new MySQL(); }
现在可以注射为
@Qualifier("main") // or @Qualifier("mysql"), to use the bean name
private DataSource dataSource;
正如注册bean有多种方法一样,命名bean也有多种方法。
@bean
有name
这个bean的名称,或者如果是复数,这个bean的别名。如果未指定,则bean的名称就是带注释的方法的名称。如果指定,则忽略方法名。
@component
及其元注释具有value
该值可以指示逻辑组件名称的建议,在自动检测组件的情况下将其转换为Spring bean。
如果未指定,则会自动为带注释的类型生成bean名称,通常是类型名称的低骆驼大小写版本。例如,myclassname
变成myclassname
作为其bean名称。Bean名称区分大小写。还要注意,错误的名称/大写通常出现在由@dependson(“my beanname”)
或XML配置文件等字符串引用的bean中。
请确保在引用bean时使用正确的名称。
Bean定义配置文件允许您有条件地注册Bean。@profile
,特别是,
指示当一个或多个指定的配置文件处于活动状态时,组件有资格注册。
@Configuration
@ComponentScan
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
System.out.println(Arrays.toString(ctx.getEnvironment().getActiveProfiles()));
System.out.println(ctx.getBean(Foo.class));
}
}
@Profile(value = "StackOverflow")
@Component
class Foo {
}
这将不显示活动配置文件,并为foo
bean抛出NoSuchBeanDefinitionException
。因为stackoverflow
配置文件不是活动的,所以bean没有注册。
相反,如果我在注册适当的配置文件时初始化applicationcontext
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("StackOverflow");
ctx.register(Example.class);
ctx.refresh();
bean已注册并可以返回/注入。
Spring大量使用AOP代理来实现高级行为。一些例子包括:
要实现这一点,Spring有两个选项:
以JDK代理为例(通过@enableasync
的默认proxyTargetClass
实现false
)
@Configuration
@EnableAsync
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
System.out.println(ctx.getBean(HttpClientImpl.class).getClass());
}
}
interface HttpClient {
void doGetAsync();
}
@Component
class HttpClientImpl implements HttpClient {
@Async
public void doGetAsync() {
System.out.println(Thread.currentThread());
}
}
这里,Spring试图找到HttpClientImpl
类型的bean,我们希望找到这个bean,因为该类型清楚地用@component
注释。然而,相反,我们得到了一个例外
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.example.HttpClientImpl] is defined
Spring包装了HttpClientIMPL
bean并通过一个只实现HttpClient
的代理
对象将其公开。这样你就可以用
ctx.getBean(HttpClient.class) // returns a dynamic class: com.example.$Proxy33
// or
@Autowired private HttpClient httpClient;
建议对接口编程。当你做不到时,你可以告诉Spring使用CGLIB代理。例如,使用@enableasync
,可以将ProxyTargetClass
设置为true
。类似的注释(enabletransactionmanagement
等)具有类似的属性。XML也将具有等价的配置选项。
Spring允许您使用ConfigurableApplicationContext#setParent(ApplicationContext)
将其他ApplicationContext
实例作为父实例构建ApplicationContext
实例。子上下文将可以访问父上下文中的bean,但反之则不然。本文将详细介绍这一点在Spring MVC中的作用。
在一个典型的Spring MVC应用程序中,您定义了两个上下文:一个用于整个应用程序(根),另一个专门用于DispatcherServlet
(路由、处理程序方法、控制器)。您可以在这里获得更多详细信息:
在这里的官方文档中也有很好的解释。
Spring MVC配置中的一个常见错误是在根上下文中使用@enableWebMVC
注释的@configuration
类或XML中的
声明WebMVC配置,但在servlet上下文中使用@controller
bean。由于根上下文无法进入servlet上下文查找任何bean,因此没有注册任何处理程序,所有请求都以404S失败。您不会看到NosuchBeanDefinitionException
,但效果是一样的。
确保您的bean在适当的上下文中注册,即。在这里可以通过为WebMVC注册的bean(HandlerMapping
、HandlerAdapter
、ViewResolver
、ExceptionResolver
等)找到它们。最好的解决方案是适当隔离豆子。DispatcherServlet
负责路由和处理请求,因此所有相关bean都应该进入它的上下文。加载根上下文的ContextLoaderListener
应该初始化应用程序所需的任何bean:服务、存储库等。
Spring以特殊的方式处理一些已知类型的bean。例如,如果您试图将moviecatalog
的数组注入到字段中
@Autowired
private MovieCatalog[] movieCatalogs;
Spring将找到moviecatalog
类型的所有bean,将它们包装在一个数组中,并注入该数组。在讨论@autowired
的Spring文档中对此进行了描述。类似的行为适用于集
、列表
和集合
注入目标。
对于map
注入目标,如果键类型是string
,Spring也会这样做。例如,如果您有
@Autowired
private Map<String, MovieCatalog> movies;
Spring将找到movieCatalog
类型的所有bean,并将它们作为值添加到map
中,其中对应的键将是它们的bean名称。
如前所述,如果没有所请求类型的bean可用,那么Spring将抛出NoSuchBeanDefinitionException
。然而,有时您只想声明这些集合类型的bean,如
@Bean
public List<Foo> fooList() {
return Arrays.asList(new Foo());
}
然后注射
@Autowired
private List<Foo> foos;
对于本身定义为集合/映射或数组类型的bean,@resource
是一个很好的解决方案,它通过唯一的名称引用特定的集合或数组bean。也就是说,从4.3开始,集合/映射和数组类型也可以通过Spring的@autowired
类型匹配算法进行匹配,只要元素类型信息保留在@bean
返回类型签名或集合继承层次结构中。在这种情况下,可以使用限定符值在相同类型的集合中进行选择,如前一段所述。
这适用于构造函数、设置器和字段注入。
@Resource
private List<Foo> foos;
// or since 4.3
public Example(@Autowired List<Foo> foos) {}
但是,对于@bean
方法(即。
@Bean
public Bar other(List<Foo> foos) {
new Bar(foos);
}
@Bean
public Bar other(@Value("#{fooList}") List<Foo> foos) {
new Bar(foos);
}
引用名为folist
的bean并注入该bean。
我有一些代码,当我运行它时会产生一个错误,说: NoSuchMethod:对null调用了方法“XYZ” 这意味着什么?我该如何修复它?
这个问题不同于关于调试异常的一般建议,因为问题的原因并不总是在调用堆栈上,而特定的建议是必要的。
问题内容: 我对Linux中的$ PATH有一些疑问。 我知道它告诉shell搜索可执行文件的目录,因此: 环境变量是什么意思? 如何改变其路径?并建议更改它? 如果我更改它,后果是什么? 问题答案: 要获取路径当前变量,请输入: 它告诉您的Shell在哪里寻找二进制文件。 是的,您可以更改它-例如,使用自定义脚本添加到文件夹。 因此:如果要执行脚本,则必须输入脚本的完整路径: 更改变量后,只需键
问题内容: 请解释以下有关Spring中的异常的信息: 这是什么意思? 在什么情况下会抛出? 我该如何预防? 问题答案: 当询问a找不到其定义的bean实例时引发异常。这可能指向不存在的bean,不唯一的bean或没有关联的bean定义的手动注册的单例实例。 A 基本上是代表Spring的容器反转的抽象。它在内部和外部向你的应用程序公开bean。当找不到或检索到这些bean时,将抛出。 以下是一个
问题内容: 我已经阅读了很多资源,但仍然坚持了解时间的复杂性。我阅读的资源是基于各种公式的,我理解这是用来表示时间复杂度的,但是我不知道如何。任何人都可以以一种可以理解的清晰方式向我解释这个原则。 问题答案: 参考:如何计算时间复杂度算法 我找到了一篇与 如何计算任何算法或程序的时间复杂度* 有关的好文章 * 计算时间复杂度最常用的指标是Big O表示法。这消除了所有恒定因素,因此当N接近无穷大时
问题内容: 我参与开发一个Java项目,该项目使用一些C ++组件,因此我需要Jacob.dll。(在Windows 7上) 无论我把Jacob.dll放在哪里,我都在不断获取。 我在寻找可能的决定,而到目前为止尚未尝试的决定是设置LD_LIBRARY_PATH变量,指向.dll文件。 我经验不足,不熟悉该变量的含义和用法-您能帮我吗? 问题答案: 通常,您必须在JVM的命令行上进行设置: