2009-09-20 20 views
7

C'è un modo in Spring per compilare automaticamente un elenco con tutti i bean di un tipo E uno qualsiasi dei suoi sottotipi? Ho un metodo setter che assomiglia:Spring list bean per tipo

setMyProp(List<MyType> list) 

E vorrei autowire in qualsiasi fagioli di MyType e tutte le sottoclassi di MyType.

Grazie, Jeff

+0

Come si desidera che questa lista di lavorare con i prototipi? Dovrebbe contenere solo un'istanza, aggiungere ogni istanza (perdita di memoria) o tornare da una qualche forma di lista di riferimento debole. –

+0

tutti i fagioli saranno singoletti nel mio caso –

risposta

24

Sì, puoi farlo. La documentazione molla dicono:

È altresì possibile prevedere tutti fagioli di un particolare tipo dal ApplicationContext aggiungendo il nota a un campo o un metodo che aspetta un array di quel tipo.

Si noti che è necessario prevedere un array, non un elenco. Questo ha senso, perché la cancellazione di un tipo generico significa che una lista potrebbe non funzionare in fase di runtime. Tuttavia, prendere il seguente test di unità, che funziona:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> 

    <bean class="test.Test.TypeB"/> 
    <bean class="test.Test.TypeC"/> 
    <bean class="test.Test.TypeD"/> 
</beans> 

e questo test di unità:

package test; 

@ContextConfiguration 
@RunWith(SpringJUnit4ClassRunner.class) 
public class Test { 

    private @Autowired List<TypeA> beans; 

    @org.junit.Test 
    public void test() { 
     assertNotNull(beans); 
     assertEquals(2, beans.size()); 
     for (TypeA bean : beans) { 
      assertTrue(bean instanceof TypeA); 
     } 
    }  

    public static interface TypeA {} 
    public static class TypeB implements TypeA {} 
    public static class TypeC extends TypeB {} 
    public static class TypeD {} 

} 

Quindi ufficialmente, si suppone di autowire TypeA[], non List<TypeA>, ma l'elenco funziona bene.

0

Risposta breve: no.

Risposta lunga: i generici Java funzionano in base alla cancellazione dei tipi, il che significa che in fase di esecuzione tale parametro è semplicemente un elenco, non un elenco di un tipo generico. In quanto tale, non è possibile capire che è pensato per essere di tipo parametro MyType, quindi non sarebbe possibile implementare questo comportamento.

Detto questo, ci sono modi alternativi per farlo. Il più ovvio sembra essere quello di ascoltare la creazione di bean e poi vedere se sono di MyType (o sottoclassi) e quindi mantenere un riferimento.

Ci sono probabilmente alcuni modi per farlo. Uno è creating a bean post-processor. In questo modo riceverai una notifica di ogni bean creato.

+3

Le informazioni sul tipo per i parametri del metodo non sono completamente cancellate e sono ancora disponibili per il runtime. È possibile accedervi tramite il metodo Method o Constructor getGenericParameterTypes. –

+0

@mik: sì ma stava parlando di un parametro su una funzione in cui tali informazioni non sono disponibili. – cletus

5

Se è possibile compilare l'elenco dal codice dell'applicazione e non dal file di definizione del bean, è possibile utilizzare lo org.springframework.beans.factory.xml.XmlBeanFactory e chiedere "getBeansOfType(MyType.class)". Questo ti dà tutti i fagioli di tipo (e sottotipo) di MyType.

+1

In realtà funziona per tutte le classi che implementano ListableBeanFactory (http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/beans/factory/ListableBeanFactory.html#getBeansOfType%28java.lang.Class% 29) –

3

Se è possibile utilizzare @Autowired all'interno del codice da compilare si può tranquillamente utilizzare il modo in cui parla skaffman. Se ti ostini a configurazione XML c'è una piccola libreria chiamata Hera per raggiungere questo obiettivo. Configurazione esentially di uno scenario descritto da voi assomiglia a questo:

<bean id="client" class=".."> 
    <property name="injectDynamicListHere"> 
     <hera:list class="my.custom.SuperType" /> 
    </property> 
</bean> 

Ciò iniettare tutti i bean Spring alto livello di attuazione SuperType come List nel fagiolo cliente.

+0

cool, grazie. Sono stato in grado di usare @Autowired nel codice, ma questo è buono a sapersi. –

+1

Forse una piccola cosa da aggiungere è che l'elenco di Hera rispetta le annotazioni @ Ordinato risp. implementazione dell'interfaccia ordinata per consentire di determinare l'ordine dei fagioli iniettati. –

0

causa di codice legacy e dispersi @Autowired ho risolto piace:

MyBean implements ApplicationContextAware{ 

    @Override 
    public void setApplicationContext(ApplicationContext ctx) throws BeansException { 
    final Map<String, HttpRequestHandlerTemplate> beansOfType = ctx.getBeansOfType(RequiredBean.class); 
    ... 
} 
Problemi correlati