一尘不染

如何在Spring XML配置中收集和注入给定类型的所有bean

spring

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
  private Collection<Option> options;

但这不违反分离原则吗?为什么我必须指定要在使用它们的相同位置(即MenuManagementBean示例中的类)使用哪些依赖项?有没有办法像这样在XML配置中注入bean的集合(在MMB类中没有任何注释)?

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

阅读 737

收藏
2020-04-16

共2个答案

一尘不染

如果你想要一种无需使用@Autowired列表即可将给定类型的所有bean收集到一个集合中的方法,那么很容易编写一个自定义的方法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来源。

2020-04-16
一尘不染

在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";
  }
}
2020-04-16