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



我正在进行基于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列表,但我必须在这里使用编程创建的上下文。

作为一种变通方法,我可以创建FooFactorybean,它将公开方法getFoos()并将此工厂连接到MyMain,但这看起来很难看。有更好的解决方案吗?

备注

  1. 尝试添加@Qualifier没有帮助
  2. 尝试使用@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"));
    }
}

最新更新