请解释以下有关NoSuchBeanDefinitionException
Spring中的异常的信息:
当BeanFactory
询问a找不到其定义的bean实例时引发异常。这可能指向不存在的bean,不唯一的bean或没有关联的bean定义的手动注册的单例实例。
A BeanFactory
基本上是代表Spring的Control
容器反转的抽象。它在内部和外部向你的应用程序公开bean。当找不到或检索到这些bean时,将抛出NoSuchBeanDefinitionException
。
以下是一个BeanFactory(
或相关类)无法找到bean的简单原因,以及如何确保找到它的原因。
Bean不存在,尚未注册
在下面的示例中
@Configuration
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
ctx.getBean(Foo.class);
}
}
class Foo {}
我们还没有Foo
通过@Bean
方法,@Component
扫描,XML定义或任何其他方式为该类型注册bean定义。在BeanFactory
由管理AnnotationConfigApplicationContext
因此没有哪里得到所要求的豆指示getBean(Foo.class)
。上面的代码片段
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 { }
在这里,一个bean定义被注册Foo过@ComponentScan。但是Spring一无所知Bar。因此,在尝试自动装配bean实例的bar字段时,它找不到对应的Foobean。抛出(嵌套在中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定义有多种方法。
@Bean
method in a @Configuration
class or
@Component
(and its meta-annotations, eg. @Repository
) through @ComponentScan
or <context:component-scan ... />
in XMLGenericApplicationContext#registerBeanDefinition
BeanDefinitionRegistryPostProcessor
…和更多。
确保你期望的bean已正确注册。
一个常见的错误是多次注册bean,即。混合以上相同类型的选项。例如,我可能有
@Component
public class Foo {}
和一个XML配置
<context:component-scan base-packages="com.example" />
<bean name="eg-different-name" class="com.example.Foo />
这样的配置将注册两个类型的bean Foo,一个带有名称foo,另一个带有名称eg-different-name。确保你不会意外注册过多的bean。这导致我们…
如果同时使用基于XML和基于注释的配置,请确保从另一个导入。XML提供
<import resource=""/>
而Java提供了@ImportResource
注释。
Expected single matching bean, but found 2 (or more)
有时,你需要针对同一类型(或接口)的多个bean。例如,你的应用程序可能使用两个数据库,一个MySQL实例和一个Oracle实例。在这种情况下,你将需要两个DataSourcebean来管理与每个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方法注册的两个bean都满足的要求BeanFactory#getBean(Class),即。他们都实行DataSource。在这个例子中,Spring没有机制来区分或区分两者。但是存在这样的机制。
你可以@Primary按照文档和本博文中的描述使用(及其等效的XML)。有了这个改变
@Bean(name = "mysql")
@Primary
public DataSource mysql() { return new MySQL(); }
之前的代码片段不会引发异常,而是返回mysqlBean。
你还可以使用@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;
没有问题。@Resource也是一种选择。
使用错误的bean名称
就像有多种注册bean的方法一样,也有多种命名它们的方法。
@Bean
有 name
此bean的名称,或者如果是复数,则为该bean的别名。如果未指定,则Bean的名称为带注释的方法的名称。如果指定,方法名称将被忽略。
<bean>
有id表示属性一个bean唯一标识符和name 可用于创建在(XML)ID非法一个或多个别名。
@Component
及其元注释具有 value
该值可能表明建议使用逻辑组件名称,以在自动检测到组件的情况下将其转换为Spring bean。
如果未指定,则会为带注释的类型(通常是该类型名称的小驼峰版本)自动生成一个Bean名称。
@Qualifier
如前所述,你可以向Bean添加更多别名。
按名称自动布线时,请确保使用正确的名称。
更高级的案例
个人资料
Bean定义配置文件使你可以有条件地注册Bean。@Profile,具体来说,
指示一个或多个指定配置文件处于活动状态时,该组件有资格注册。
概要文件是一个命名的逻辑组,可以通过ConfigurableEnvironment.setActiveProfiles(java.lang.String...)
将该spring.profiles.active属性设置为JVM系统属性,环境变量或Web应用程序的web.xml中的Servlet上下文参数来以编程方式激活或以声明方式激活 。概要文件也可以通过@ActiveProfiles
注释在集成测试中以声明方式激活。
考虑以下示例,其中spring.profiles.active
未设置属性。
@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 {
}
这将不显示任何活动配置文件,并NoSuchBeanDefinitionException
为Fo
o Bean 抛出一个。由于StackOverflow
概要文件未处于活动状态,因此未注册Bean。
相反,如果我ApplicationContext
在注册适当的配置文件时初始化了
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("StackOverflow");
ctx.register(Example.class);
ctx.refresh();
Bean已注册,可以返回/注入。
AOP Proxies
Spring 大量使用AOP代理来实现高级行为。一些示例包括:
@Transactional
@Cacheable
@Async
and @Scheduled
为此,Spring有两个选择:
@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,因为该类型明显地带有注释@Component
。但是,相反,我们得到了一个例外
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.example.HttpClientImpl] is defined
Spring包装HttpClientImplBean
并通过Proxy仅实现的对象对其进行暴露HttpClient
。所以你可以用
ctx.getBean(HttpClient.class) // returns a dynamic class: com.example.$Proxy33
// or
@Autowired private HttpClient httpClient;
始终建议对接口进行编程。如果不能,则可以告诉Spring使用CGLIB代理。例如,使用@EnableAsync
,你可以设置proxyTargetClass为true。相似的注释(EnableTransactionManagement等)具有相似的属性。XML也将具有等效的配置选项。
ApplicationContext Hierarchies - Spring MVC
通过Spring,你可以ApplicationContext
使用,以其他ApplicationContext
实例作为父实例来构建实例ConfigurableApplicationContext#setParent(ApplicationContext)
。子上下文可以在父上下文中访问bean,但事实并非如此。这篇文章详细介绍了什么时候有用,尤其是在Spring MVC中。
在典型的Spring MVC应用程序中,你定义了两个上下文:一个用于整个应用程序(根),另一个专门用于DispatcherServlet
(路由,处理程序方法,控制器)。你可以在此处获得更多详细信息:
Spring Framework中applicationContext.xml和spring-servlet.xml之间的区别
在此处的官方文档中也对此进行了很好的解释。
Spring MVC配置中的一个常见错误是在带有@EnableWebMvc注释@Configuration
类或<mvc:annotation-driven />XML
的根上下文中声明WebMVC配置,但@Controller
在Servlet上下文中声明Bean。由于根上下文无法进入servlet上下文以查找任何bean,因此没有注册任何处理程序,并且所有请求均以404失败。你不会看到NoSuchBeanDefinitionException
,但是效果是一样的。
确保你的bean在适当的上下文中注册,即。在那里他们可以通过用于WebMVC(注册豆中找到HandlerMapping,HandlerAdapter,ViewResolver,ExceptionResolver
,等等)。最好的解决方案是正确隔离豆。该DispatcherServlet
负责路由和处理请求,因此所有相关Bean应该进入它的上下文。ContextLoaderListener
,它加载根上下文,应该初始化任何豆的应用需求的其余部分:服务,仓库等。
Arrays, collections, and maps
Spring会以特殊方式处理某些已知类型的Bean。例如,如果你尝试将的数组MovieCatalog注入字段
@Autowired
private MovieCatalog[] movieCatalogs;
Spring将找到所有类型的bean MovieCatalog
,将它们包装在一个数组中,然后注入该数组。在Spring文档讨论中@Autowired
对此进行了描述。类似的行为适用于Set,List
和Collection
注射的目标。
对于Map
注入目标,如果键类型为,Spring也将以这种方式运行String
。例如,如果你有
@Autowired
private Map<String, MovieCatalog> movies;
Spring将查找所有类型的bean,MovieCatalog
并将它们作为值添加到Map
,其中相应的键将是它们的bean名称。
如前所述,如果没有可用的请求类型的bean,Spring将抛出NoSuchBeanDefinitionException
。但是,有时候,你只想声明这些集合类型的bean,例如
@Bean
public List<Foo> fooList() {
return Arrays.asList(new Foo());
}
并注入它们
@Autowired
private List<Foo> foos;
在此示例中,Spring
将失败,NoSuchBeanDefinitionException
因为Foo你的上下文中没有bean。但是你不想要Foo
bean,你想要List<Foo>
bean。在Spring 4.3之前,你必须使用@Resource
对于本身定义为集合/映射或数组类型的bean,这@Resource
是一个很好的解决方案,通过唯一名称引用特定的集合或数组bean。也就是说,从4.3版本开始,@Autowired
只要元素类型信息保留在@Bean
返回类型签名或集合继承层次结构中,就可以通过Spring的类型匹配算法来匹配集合/映射和数组类型 。在这种情况下,可以使用限定符值在同类型的集合中进行选择,如上一段所述。
这适用于构造函数,setter和字段注入。
@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);
}
在这里,Spring忽略任何方法@Resource
或@Autowired
注释方法,因为它是@Bean
方法,因此无法应用文档中描述的行为。但是,你可以使用Spring Expression Language(SpEL)
来按其名称引用bean。在上面的示例中,你可以使用
@Bean
public Bar other(@Value("#{fooList}") List<Foo> foos) {
new Bar(foos);
}
引用命名的bean fooList
并将其注入。
问题内容: 什么是空指针异常,什么原因导致它们? 可以使用哪些方法/工具确定原因,以阻止异常导致程序过早终止? 问题答案: 声明引用变量(即对象)时,实际上是在创建指向对象的指针。考虑以下代码,在其中声明基本类型的变量int: 在此示例中,变量是an ,Java会0为你初始化它。当你10在第二行为其分配值时,你的值将写入所指的存储位置x。 但是,当你尝试声明引用类型时,会发生一些不同的事情。采取以
问题内容: 我一直在搜索,但仍然不确定“盐”是什么以及如何使用/实现它。对不起这个问题,我是自学php。 问题答案: 我绝对不是专家,但是真正简短的答案是“涂一行”文本意味着在其末尾添加一些额外的字符。您可以将“ salt”和“ abcdefg”加盐以获得“ saltabcdefg”。如果“盐”恰好是您想要使其更难猜测的密码,则这可能很有用。 通常,密码+盐会通过一些难以逆转的过程转换(“散列”)
请解释Spring中关于异常的以下内容: 这是什么意思? 在什么条件下抛出? 如何预防? 这篇文章是关于使用Spring的应用程序中出现的全面问答。
正在启动lib\main。在调试模式下为x86构建的Android SDK上的dart。。。正在运行Gradle任务“assembleDebug”。。。 失败:生成失败,出现异常。 错误:任务“:app:compileFlutterBuildDebug”的执行失败 JAVAlang.NullPointerException(无错误消息) > 尝试:使用--stacktrace选项运行以获取堆栈跟踪
当我试图通过heroku打开我正在处理的应用程序时,我得到了一个应用程序错误。我查看了heroku日志,发现以下错误: “错误H10(应用程序崩溃)- 我不确定错误指的是什么,或者我如何解决导致错误的问题。你能给的任何帮助都会很棒!
问题内容: 我有以下代码: 当我在Python shell中运行它时,它返回: 我已经搜索过了,这似乎叫做列表理解,但是它如何工作? 问题答案: 我有以下代码: 当我在Python shell中运行它时,它返回: 我已经搜索过了,这似乎叫做列表理解,但是它如何工作?