Spring框架最重要的特征之一就是依赖注入概念。我理解背后的建议之一是将一般的高级机制与低级细节分开(如Dependency Inversion Principle所宣布)。
从技术上讲,这可以归结为让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>
但是,如果我想拥有一种在多个从属bean上运行的高级机制,该怎么办?
public class MenuManagementBean { private Collection<Option> options; public void printOut() { for (Option option:options) { // do something for option } //... } }
我知道一种解决方案是@Autowired在单例bean中使用批注,即…
@Autowired
@Autowired private Collection<Option> options;
但这不违反分离原则吗?为什么我必须指定要在使用它们的相同位置(即MenuManagementBean示例中的类)使用哪些依赖项?有没有办法像这样在XML配置中注入bean的集合(在MMB类中没有任何注释)?
MenuManagementBean
MMB
<bean class="MenuManagementBean"> <property name="options"> <xxx:autowire by-type="MyOptionImpl"/> </property> </bean>
如果你想要一种无需使用@Autowired列表即可将给定类型的所有bean收集到一个集合中的方法,那么很容易编写一个自定义的方法FactoryBean来为你做这件事:
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的情况-没有编译时依赖性,也不知道SoC的options来源。
options
在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"; } }