代码之家  ›  专栏  ›  技术社区  ›  Grzegorz Oledzki

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

  •  23
  • Grzegorz Oledzki  · 技术社区  · 16 年前

    spring框架最突出的特点之一是 Dependency Injection 概念。我理解其中一个建议,就是将一般的高层机制与低层细节分开(如 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>
    
    3 回复  |  直到 16 年前
        1
  •  26
  •   skaffman    16 年前

    没有现成的工具可以做到这一点,没有。但是,如果您想要一种不使用@autowired list将给定类型的所有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的侵犯,如果是的话-没有编译时依赖,也不知道 options 来自。

        2
  •  35
  •   takacsot    13 年前

    老问题,在春季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";
      }
    }
    
        3
  •  5
  •   Johanna    16 年前

    使用上下文文件替代@autowired: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-autowire

    所以你会:

    <bean class="MenuManagementBean" autowire="byType" />
    

    可以将其他属性指定为normal,这将只覆盖这些属性的自动连接。