Подтвердить что ты не робот

Как собирать и вводить все beans данного типа в конфигурации Spring XML

Одним из самых сильных акцентов в структуре Spring является концепция Dependency Injection. Я понимаю, что один из советов заключается в том, чтобы отделить общий механизм высокого уровня от низкоуровневых деталей (как объявлено Принцип инверсии зависимостей).

Технически это сводится к тому, что реализация bean должна знать как можно меньше о bean, который вводится как зависимость, например.

public class PrintOutBean {
    private LogicBean logicBean;
    public void action() {
        System.out.println(logicBean.humanReadableDetails());
    }
    //...
}

<bean class="PrintOutBean">
    <property name="loginBean" ref="ShoppingCartBean"/>
</bean>

Но что, если бы я хотел иметь механизм высокого уровня, работающий на нескольких зависимых beans?

  public class MenuManagementBean {
       private Collection<Option> options;
       public void printOut() {
            for (Option option:options) {
              // do something for option
            }
            //...
       }
  }

Я знаю, что одним решением было бы использовать аннотацию @Autowired в singleton bean, то есть...

  @Autowired
  private Collection<Option> options;

Но разве это не нарушает принцип разделения? Почему я должен указать, какие иждивенцы взять в том же месте, где я их использую (т.е. MenuManagementBean класс в моем примере)? Есть ли способ встраивать коллекции beans в такую ​​конфигурацию XML (без какой-либо аннотации в классе MMB)?

<bean class="MenuManagementBean">
    <property name="options">
       <xxx:autowire by-type="MyOptionImpl"/>
    </property>
 </bean>
4b9b3361

Ответ 1

Нет никакого готового средства для этого, нет. Однако, если вам нужен способ собрать все beans данного типа в коллекцию, не используя @Autowired list, тогда легко написать пользовательский FactoryBean, чтобы сделать это для вас:

public class BeanListFactoryBean<T> extends AbstractFactoryBean<Collection<T>> {

    private Class<T> beanType;
    private @Autowired ListableBeanFactory beanFactory;

    @Required
    public void setBeanType(Class<T> beanType) {
        this.beanType = beanType;
    }

    @Override
    protected Collection<T> createInstance() throws Exception {
        return beanFactory.getBeansOfType(beanType).values();
    }

    @Override
    public Class<?> getObjectType() {
        return Collection.class;
    }    
}

а затем

 <bean class="MenuManagementBean">
    <property name="options">
       <bean class="BeanListFactoryBean">
          <property name="beanType" class="MyOptionImpl.class"/>
       </bean>
    </property>
 </bean>

Однако, это все, кажется, требует больших усилий, чтобы не помещать @Autowired в ваш первоначальный класс. Это не так много из-за нарушения SoC, если оно вообще есть - нет зависимости от compiltime и не знает, откуда происходит options.

Ответ 2

Старый вопрос и в Spring 3.1 можно:

public class PluginPrototypeTest extends ASpringWebTest {
  @Autowired
  Collection<IDummyRepo> repos;

  @Test
  public void cacheTest() {
    assertNotNull(repos);
    assertEquals(2, repos.size());
    for(IDummyRepo r: repos){
      System.out.println(r.getName());
    }
  }
}

@Repository
public class DummyRepo implements IDummyRepo {
  @Override
  public String getName(){
    return "DummyRepo";
  }
}
@Repository
public class DummyRepo2 implements IDummyRepo {
  @Override
  public String getName(){
    return "DummyRepo2";
  }
}

Ответ 3

Альтернатива @Autowired, используя файл контекста: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-autowire

Итак, у вас будет:

<bean class="MenuManagementBean" autowire="byType" />

Другие свойства могут быть указаны, как обычно, и это приведет к переопределению автоустановки только для этих свойств.