2009-09-20 21 views
7

¿Existe algún modo en Spring de que pueda completar automáticamente una lista con todos los beans de un tipo Y cualquiera de sus subtipos? Tengo un método de selección que se parece a:Spring list beans por tipo

setMyProp(List<MyType> list) 

Y me gustaría Autowire en cualquier granos de MyType y todas las subclases de MyType.

Gracias, Jeff

+0

¿Cómo quieres esta lista para trabajar con prototipos? En caso de que contenga solo una instancia, agregue cada instancia (fuga de memoria) o regrese mediante algún tipo de lista de referencia débil. –

+0

todos los beans serán singletons en mi caso –

Respuesta

24

Sí, puede hacer esto. Los docs resorte dicen:

También es posible proporcionar todos los granos de un tipo particular de la ApplicationContext mediante la adición de la anotación a un campo o método que espera una matriz de ese tipo.

Tenga en cuenta que dice que necesita esperar una matriz, no una lista. Esto tiene sentido, porque el borrado de tipo genérico significa que una lista puede no funcionar en tiempo de ejecución. Sin embargo, tomar la siguiente prueba de la unidad, que funciona:

<?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> 

y esto prueba de unidad:

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

} 

Así oficialmente, que se supone que Autowire TypeA[], no List<TypeA>, pero la lista funciona bien.

0

Respuesta corta: no.

Respuesta larga: los genéricos de Java funcionan por tipo borrado, lo que significa que en tiempo de ejecución ese parámetro es simplemente una Lista, no una Lista de un tipo genérico. Como tal, no se puede deducir que debe ser del tipo de parámetro MyType, por lo que no sería posible implementar este comportamiento.

Dicho esto, hay formas alternativas de hacerlo. El más obvio parece ser escuchar la creación de frijol y luego ver si son de MyType (o subclases) y luego mantener una referencia.

Probablemente existan algunas formas de hacerlo. Uno es creating a bean post-processor. De esta manera recibirás una notificación de cada bean creado.

+3

La información de tipo para los parámetros del método no se borra completamente y todavía está disponible para el tiempo de ejecución. Puede acceder a esto a través del método Method o Constructor getGenericParameterTypes. –

+0

@mik: sí, pero él estaba hablando de un parámetro en una función donde no hay tal información disponible. – cletus

5

Si es aceptable para llenar la lista de su código de aplicación y no desde dentro del archivo de definición de frijol podría utilizar el org.springframework.beans.factory.xml.XmlBeanFactory y pedirle que "getBeansOfType(MyType.class)". Esto le proporciona todos los beans de tipo (y subtipo) de MyType.

+1

Esto realmente funciona para todas las clases que implementan ListableBeanFactory (http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/beans/factory/ListableBeanFactory.html#getBeansOfType%28java.lang.Class% 29) –

3

Si puede usar @Autowired dentro del código que se va a poblar, puede usar de manera segura el modo mencionado por skaffman. Si insistes en la configuración XML, hay una pequeña biblioteca llamada Hera para lograr esto. configuración de absoluto se refiere a un escenario descrito por que se parece a esto:

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

Esto inyectará todos los granos de primavera de alto nivel de ejecución SuperType como List en el grano de cliente.

+0

genial, gracias. Pude usar @Autowired en el código, pero es bueno saberlo. –

+1

Quizás una cosa menor de agregar es que la lista de Hera respeta las anotaciones @Ordered resp. implementando la interfaz ordenada para permitir determinar el orden de los beans inyectados. –

0

Debido al código heredado y desaparecidos @Autowired lo resuelvo gusta:

MyBean implements ApplicationContextAware{ 

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