2010-05-09 6 views
22

Jednym z najsilniejszych akcentów struktury Spring jest koncepcja Dependency Injection. Rozumiem, że jedną z porad jest oddzielenie ogólnego mechanizmu wysokiego poziomu od szczegółów niskiego poziomu (zgodnie z zapowiedzią Dependency Inversion Principle).Jak zbierać i wstrzykiwać wszystkie fasole danego typu w konfiguracji Spring XML

Z technicznego punktu widzenia sprowadza się to do implementacji fasoli, aby wiedzieć jak mało o wstrzykiwaniu fasoli jako zależności, np.

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

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

Ale co, gdybym chciał mieć mechanizm wysokiego poziomu działający na wielu zależnych ziarnach fasoli?

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

wiem jedno rozwiązanie byłoby użyć @Autowired adnotacji w singleton fasoli, czyli ...

@Autowired 
    private Collection<Option> options; 

Ale nie to naruszać zasadę separacji? Dlaczego muszę określać, jakie zależności należy wybrać w tym samym miejscu, w którym je używam (np. MenuManagementBean w moim przykładzie)? Czy istnieje sposób na wstrzyknięcie kolekcji fasoli w konfiguracji XML w ten sposób (bez adnotacji w klasie MMB)?

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

Nie sądzę dodanie @Autowired pola stworzy kolekcję opcji dla Ciebie - to musisz zadeklarować fasoli w twój kontekst zawierający listę opcji. A potem równie dobrze możesz rzucić @Autowired i umieścić w definicji kontekstu MMB. – mdma

+3

@mdma: Jestem pewien, że dodanie '@ Autowired' do właściwości collection pozwala na zebranie wszystkich komponentów typu collection. W ten sposób używamy go cały czas. Dokumentacja wiosna 2.5: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-autowired-annotation –

+0

Dobra, dobra funkcja! Sprawdziłem dokumenty, ale nie widziałem tego, kiedy patrzyłem. Przepraszam za zamieszanie. – mdma

Odpowiedz

26

Nie ma gotowego urządzenia do tego, nie. Jednakże, jeśli chcesz sposobu zbierania wszystkich ziaren danego rodzaju w kolekcji, bez korzystania z listy @Autowired, to łatwo napisać zwyczaj FactoryBean to zrobić dla Ciebie:

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; 
    }  
} 

a następnie

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

Jednak to wszystko wydaje się być dużym wysiłkiem, aby uniknąć umieszczenia @Autowired w oryginalnej klasie. Nie ma to większego znaczenia z SoC, jeśli w ogóle jest - nie ma zależności compiltime i nie wiadomo skąd pochodzą options.

+0

Niestandardowe FactoryBean: Na pierwszy rzut oka to rozwiązanie nie pozwala mi określić dwóch (lub więcej) kolekcji, które mają być autowyredowane według typu i wstrzykiwane jako jedna kolekcja. Nie oświadczyłem tego w pytaniu, ale pomyślałem, że może być użyteczne. –

+0

Jeśli chodzi o naruszenie zasad SoC: Widzę twoją sprawę, ale nadal uważam, że coś jest nie w porządku. Co jeśli mam opracować i dostarczyć komponent wysokiego poziomu ("MenuManagementBean" w moim przykładzie) w mojej bibliotece, a następnie jakiś projekt zależny powinien móc z niego skorzystać? –

+0

@Grzegorz: Wstrzyknij fasolę fabryczną za pomocą 'Option.class' zamiast' MyOptionImpl.class', która powinna dostarczyć wszystkie fasole implementujące interfejs. – skaffman

33

Old pytanie wiosną 3.1 możliwe jest:

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"; 
    } 
} 
+2

Uważam, że pierwotne żądanie polegało na unikaniu używania adnotacji, aby uniknąć używania XML ... – Jules

Powiązane problemy