java - para - que es spring
Cómo recopilar e inyectar todos los beans de un tipo determinado en la configuración Spring XML (3)
Uno de los acentos más fuertes del marco Spring es el concepto de Inyección de Dependencia . Entiendo que uno de los consejos detrás de esto es separar el mecanismo general de alto nivel de los detalles de bajo nivel (según lo anunciado por el Principio de Inversión de Dependencia ).
Técnicamente, eso se reduce a tener una implementación de frijol para saber lo menos posible acerca de que un frijol sea inyectado como una dependencia, por ejemplo
public class PrintOutBean {
private LogicBean logicBean;
public void action() {
System.out.println(logicBean.humanReadableDetails());
}
//...
}
<bean class="PrintOutBean">
<property name="loginBean" ref="ShoppingCartBean"/>
</bean>
Pero, ¿y si quisiera tener un mecanismo de alto nivel operando en múltiples beans dependientes?
public class MenuManagementBean {
private Collection<Option> options;
public void printOut() {
for (Option option:options) {
// do something for option
}
//...
}
}
Sé que una solución sería usar la anotación @Autowired
en el bean singleton, es decir ...
@Autowired
private Collection<Option> options;
Pero, ¿no viola el principio de separación? ¿Por qué tengo que especificar qué dependientes tomar en el mismo lugar donde los uso (es decir, la clase MenuManagementBean
en mi ejemplo)? ¿Hay alguna forma de inyectar colecciones de beans en la configuración XML como esta (sin ninguna anotación en la clase MMB
)?
<bean class="MenuManagementBean">
<property name="options">
<xxx:autowire by-type="MyOptionImpl"/>
</property>
</bean>
Alternativa a @Autowired, utilizando un archivo de contexto: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-autowire
Entonces tendrías:
<bean class="MenuManagementBean" autowire="byType" />
Se pueden especificar otras propiedades, como es normal, y eso anularía el autoenvío solo para esas propiedades.
No hay instalaciones listas para usar para hacer esto, no. Sin embargo, si quiere una forma de recopilar todos los beans de un tipo dado en una colección, sin usar una lista @Autowired, entonces es fácil escribir un FactoryBean
personalizado para que lo haga por usted:
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;
}
}
y entonces
<bean class="MenuManagementBean">
<property name="options">
<bean class="BeanListFactoryBean">
<property name="beanType" class="MyOptionImpl.class"/>
</bean>
</property>
</bean>
Sin embargo, todo esto parece un gran esfuerzo para evitar poner @Autowired
en su clase original. No es una gran violación de SoC, si es que lo es, no hay dependencia de tiempo de compilación y no se sabe de dónde provienen las options
.
Pregunta anterior y en primavera 3.1 es posible:
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";
}
}