我正在进行基于spring的项目,在该项目中,我们使用构造函数注入并使用@Configuration
配置上下文。
这是一个简化的例子,说明了我的问题。
我有一个bean MyMainBean
,它指的是Foo
bean的集合:
public class MyMainBean {
private Collection<Foo> foos;
public MyMainBean(Collection<Foo> foos) {
this.foos = foos;
}
}
这是bean Foo
:
public class Foo {
private final String name;
public Foo(String name) {
this.name = name;
}
public void foo(String arg) {
System.out.println("foo (" + name + "): " + arg);
}
}
以下是配置类的样子:
@Configuration
public class AppConfig {
@Bean
public MyMainBean myMain(Collection<Foo> foos) {
return new MyMainBean(foos);
}
@Bean
public Collection<Foo> foos() {
System.out.println("foos");
return Arrays.asList(new Foo("colletion1"), new Foo("colletion2"));
}
}
当我运行此程序时,我会收到异常消息:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.hello.impl.Foo] found for dependency [collection of com.hello.impl.Foo]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
消息非常清楚,所以尽管这不是我所需要的,但我在AppConfig
中添加了以下方法:
@Bean
public Foo foo1() {
System.out.println("foo1");
return new Foo("single1");
}
和类似的foo2()
现在上下文运行,bean连接。但是,尽管foo1()
、foo2()
和foos()
被调用,但MyAppBean
在其构造函数集合中接收,该集合包含由foo1()
和foo2()
创建的2个元素。
我想让foos()
工作,因为在我的真实代码中,类似的方法使用配置动态检索Foo
的列表。我相信这里缺少了一些神奇的注释,因为我可以使用context.xml
创建bean列表,但我必须在这里使用编程创建的上下文。
作为一种变通方法,我可以创建FooFactory
bean,它将公开方法getFoos()
并将此工厂连接到MyMain
,但这看起来很难看。有更好的解决方案吗?
备注
- 尝试添加
@Qualifier
没有帮助 - 尝试使用
@Autowire
和@Resource
而不是构造函数注入也没有帮助
由于两个@Bean
都是在同一个AppConfig
中声明的,因此您可以像以下这样修复问题:
@Bean
public MyMainBean myMain() {
return new MyMainBean(foos());
}
在不同@Configuration
类别的情况下,@Resource
会进行救援:
@Resource(name="foos")
private Collection<Foo> foos;
在这种情况下,即使使用@Qualifier
,@Autowire
也没有帮助。
有点晚了,但现在是:
@Configuration
public class AppConfig {
// Answer 1 : Inject the "foos" collection bean using @Value instead of @Qualifier
@Bean
public MyMainBean myMain1(@Value("#{foos}") Collection<Foo> foos) {
return new MyMainBean(foos);
}
// Answer 2 : call directly foos() since @Configuration bean is proxified,
// "foos" collection bean will only be called and instanciated once (at first call)
@Bean
public MyMainBean myMain2() {
return new MyMainBean(foos());
}
@Bean
public Collection<Foo> foos() {
System.out.println("foos");
return Arrays.asList(new Foo("colletion1"), new Foo("colletion2"));
}
}