Spring DI:指定FactoryBean <t> </t>的默认组件

时间:2012-01-17 19:45:59

标签: java spring inversion-of-control

我有两个接口IFoo的实现:Foo1Foo2

我需要上下文能够为任何想要IFoo的类注入正确的上下文而不知道它将获得什么实现(因此不使用@Qualifier)。

使用示例:

class Bar { 
  @Autowired IFoo foo;
}

我有一个FactoryBean<IFoo>类,其中包含返回的逻辑。

问题在于我也想让这两个人通过IOC,因为他们自己有依赖。

public class FooFactory implements FactoryBean<Foo> {
  @Autowired Foo1 foo1;
  @Autowired Foo2 foo2;

  @Override
  public IFoo getObject() throws Exception {
    if(someLogic()){
        return foo1;
    }
    return foo2;
   }
} 

如果我将它们自动装入工厂,我会得到

的例外
"No unique bean of type IFoo is defined: expected single matching bean but found 3: [fooFactory, foo1, foo2]"

任何方式告诉spring只为其他人使用默认的fooFactory但是在工厂内使用这两个实现?

4 个答案:

答案 0 :(得分:1)

您可以注入一个列表:

@Resource
private List<IFoo> foos;

不幸的是,由于您当前正在构建FooFactory,因此可能无效,因此您可能会遇到循环依赖性错误。试试吧!

但是自从Spring 3.1开始使用@Profile@Configuration时,更惯用的操作:

@Bean
public IFoo foo() {
  if(someCondition) {
    return new Foo1(dep1(), dep2());
  else
    return new Foo1(dep3(), dep4());
}

其中dep...()方法也是@Bean声明。

答案 1 :(得分:1)

您可以使用@Primary来修改工厂结果。

我还没有尝试过,并且没有IDE来测试它,但可能有效。

@Configuration
public class MyFactory {

  @Bean
  @Primary
    public IFoo getFoo () {
    ...
  }
}

答案 2 :(得分:1)

您可以使用“主要”bean的概念。假设您正在使用XML配置,那么:

<bean id="fooFactory" class="x.y.FooFactory" primary="true"/>

现在,@Autowired IFoo foo应该选择工厂的结果,而不是foo1foo2 bean。

我还建议在工厂内使用@Resource,而不是@Autowired,即

public class FooFactory implements FactoryBean<Foo> {
  @Resource Foo1 foo1;
  @Resource Foo2 foo2;

这降低了自动装配追逐自己尾部的几率,因为@Resource将注入一个特定的命名bean(即foo1foo2)。您仍在@Autowired中使用Bar

如果您使用@Resource,那么使用primary="true"的替代方法是从自动装配中排除foo1foo2 bean,例如

<bean id="foo1" class="x.y.Foo1" autowire-candidate="false"/>

答案 3 :(得分:0)

看一下bean工厂范围。