Spring DI: укажите компонент по умолчанию для FactoryBean <T> - PullRequest
1 голос
/ 17 января 2012

У меня есть две реализации интерфейса IFoo: Foo1 и Foo2.

Мне нужен контекст, чтобы иметь возможность вставлять правильный для любого класса, который хочет IFoo без того, чтобы этот класс не знал, какую реализацию он собирается получить (поэтому не нужно использовать @Qualifier).

Пример использования:

class Bar { 
  @Autowired IFoo foo;
}

У меня есть класс FactoryBean<IFoo>, в котором есть логика, которую нужно вернуть.

Проблема в том, что я также хочу, чтобы эти два имплиса прошли через МОК, потому что они сами имеют зависимости.

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 ]

1 голос
/ 18 января 2012

Вы можете использовать понятие «основной» боб. Предполагая, что вы используете конфигурацию XML, тогда:

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

Теперь @Autowired IFoo foo должен выбрать результат фабрики, предпочтительнее бобов foo1 и foo2.

Я бы также рекомендовал использовать @Resource внутри самой фабрики, а не @Autowired, т.е.

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

Это уменьшает вероятность того, что автопроводка будет преследовать свой собственный хвост, поскольку @Resource будет вводить определенный, названный компонент (т.е. foo1 и foo2). Вы бы все еще использовали @Autowired в Bar.

Если вы используете @Resource подобным образом, то альтернативой для использования primary="true" является исключение бобов foo1 и foo2 из автопроводки, например,

<bean id="foo1" class="x.y.Foo1" autowire-candidate="false"/>
1 голос
/ 18 января 2012

Вы можете аннотировать результат factorys с помощью @Primary.

Я не пробовал, и у меня нет IDE здесь, чтобы проверить это, но может это сработает.

@Configuration
public class MyFactory {

  @Bean
  @Primary
    public IFoo getFoo () {
    ...
  }
}
1 голос
/ 17 января 2012

Вы можете добавить список:

@Resource
private List<IFoo> foos;

К сожалению, это может не сработать, так как вы в настоящее время создаете FooFactory, поэтому вы можете получить циклическую ошибку зависимости.Попробуйте!

Но более идиоматическим wat с Spring 3.1 будет использование @Profile или @Configuration:

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

, где dep...() методы также являются @Bean объявлениями

0 голосов
/ 18 января 2012

Взгляните на возможности фабрики бобов.

...