使用注释将bean的集合注入构造函数

时间:2014-05-07 08:15:52

标签: java spring configuration dependency-injection

我正在开发基于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,但这看起来很难看。有更好的解决方案吗?

说明

  1. 尝试添加@Qualifier没有帮助
  2. 尝试使用@Autowire@Resource而不是构造函数注入也没有用。

2 个答案:

答案 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"));
    }
}