我正在开发基于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
而不是构造函数注入也没有用。答案 0 :(得分:2)
由于两个@Bean
都在同一个AppConfig
中声明,因此您可以解决以下问题:
@Bean
public MyMainBean myMain() {
return new MyMainBean(foos());
}
如果@Configuration
个班级不同,@Resource
就会出现问题:
@Resource(name="foos")
private Collection<Foo> foos;
即使使用@Autowire
,@Qualifier
在这种情况下也无济于事。
答案 1 :(得分:0)
有点晚了,但我们在这里:
@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"));
}
}