Java 什么是NoSuchBeanDefinitionException,如何修复它?
请解释以下关于春季无此类定义异常的内容:Java 什么是NoSuchBeanDefinitionException,如何修复它?,java,spring,applicationcontext,Java,Spring,Applicationcontext,请解释以下关于春季无此类定义异常的内容: 这是什么意思 在什么条件下会抛出 我怎样才能预防它 这篇文章是关于在使用Spring的应用程序中出现的NoSuchBeanDefinitionException的综合性问答。 当一个BeanFactory被请求一个 它找不到一个定义。这可能指向一个不存在的问题 bean、非唯一bean或手动注册的单实例 没有关联的bean定义 A基本上是表示的抽象。它向您的应用程序在内部和外部公开bean。当它找不到或检索不到这些bean时,它会抛出一个NoSuc
- 这是什么意思
- 在什么条件下会抛出
- 我怎样才能预防它
这篇文章是关于在使用Spring的应用程序中出现的
NoSuchBeanDefinitionException
的综合性问答。
当一个BeanFactory
被请求一个
它找不到一个定义。这可能指向一个不存在的问题
bean、非唯一bean或手动注册的单实例
没有关联的bean定义
A基本上是表示的抽象。它向您的应用程序在内部和外部公开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 {}
我们没有通过@bean
方法、@Component
扫描、XML定义或任何其他方式为类型Foo
注册bean定义。因此,由AnnotationConfigApplicationContext
管理的BeanFactory
没有指示从何处获取由getBean(Foo.class)
请求的bean。上面的片段抛出
线程“main”org.springframework.beans.factory.NoSuchBean定义异常中的异常:
没有定义[com.example.Foo]类型的限定bean
类似地,在尝试满足@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(name = "mysql")
@Qualifier(value = "main")
public DataSource mysql() { return new MySQL(); }
这里,通过@ComponentScan
为Foo
注册bean定义。但是Spring对Bar
一无所知。因此,在尝试自动连接Foo
bean实例的bar
字段时,它无法找到相应的bean。它抛出(嵌套在
由以下原因引起:org.springframework.beans.factory.noSuchBean定义异常:
没有为依赖项[com.example.Bar]找到类型为[com.example.Bar]的符合条件的bean:
至少需要1个符合此依赖项autowire候选项条件的bean。依赖项注释:{@org.springframework.beans.factory.annotation.Autowired(required=true)}
注册bean定义有多种方法
方法在@Bean
类中或@Configuration
在XML配置中
(及其元注释,例如@Component
)通过@Repository
或@ComponentScan
以XML格式- 手动通过
- 通过BeanDefinitionRegistryPostProcessor手动执行
@Component
public class Foo {}
以及一个带有
<context:component-scan base-packages="com.example" />
<bean name="eg-different-name" class="com.example.Foo />
而Java提供了注释
需要单个匹配bean,但找到2个(或更多)
有时,您需要为同一类型(或接口)使用多个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 {}
投掷
线程“main”org.springframework.beans.factory.NoniqueBeandDefinitionException中的异常:
未定义[com.example.DataSource]类型的合格bean:
应为单个匹配bean,但找到2:oracle、mysql
因为通过@Bean
方法注册的两个Bean都满足的要求,即它们都实现了数据源
。在本例中,Spring没有机制来区分这两者或区分它们的优先级。但这种机制是存在的
您可以使用和中所述的(及其在XML中的等效项)。有了这个变化
@Bean(name = "mysql")
@Primary
public DataSource mysql() { return new MySQL(); }
前面的代码段不会抛出异常,而是返回mysql
bean
您还可以使用@Qualifier
(及其在XML中的等效项)对bean选择过程进行更多控制,如中所述。虽然@Autowired
主要用于按类型自动连线,但@Qualifier
允许按名称自动连线。比如说,
@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(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也有多种方法
有
这个bean的名称,或者如果是复数,这个bean的别名。如果留下
未指定bean的名称是带注释方法的名称。
如果指定,将忽略方法名称
具有id
属性来表示bean的唯一标识符,name
可用于在(XML)id中创建一个或多个非法别名
而且它的元注释
该值可能表示对逻辑组件名称的建议,以
在自动检测到组件的情况下,将转换为SpringBean
如果未指定,则会自动为带注释的类型生成bean名称,通常是类型名称的小写版本。例如,MyClassName
变成了MyClassName
作为它的bean名。Bean名称区分大小写。还要注意,错误的名称/大小写通常出现在由字符串@DependsOn(“my BeanName”)
或XML配置文件引用的bean中
如前所述,@Qualifier
允许您向bean添加更多别名
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("StackOverflow");
ctx.register(Example.class);
ctx.refresh();
@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());
}
}
ctx.getBean(HttpClient.class) // returns a dynamic class: com.example.$Proxy33
// or
@Autowired private HttpClient httpClient;
@Autowired
private MovieCatalog[] movieCatalogs;
@Autowired
private Map<String, MovieCatalog> movies;
@Bean
public List<Foo> fooList() {
return Arrays.asList(new Foo());
}
@Autowired
private List<Foo> foos;
@Resource
private List<Foo> foos;
// or since 4.3
public Example(@Autowired List<Foo> foos) {}
@Bean
public Bar other(List<Foo> foos) {
new Bar(foos);
}
@Bean
public Bar other(@Value("#{fooList}") List<Foo> foos) {
new Bar(foos);
}