区分从不同弹簧配置文件加载的bean

时间:2009-06-07 14:30:07

标签: java spring

我们的项目基于Spring IoC,它提供了轻松的可扩展性,这意味着我们的项目功能通过我们称之为扩展(或插件)的扩展来扩展,这些扩展提供了一些额外的Spring xml配置文件+新代码。

问题是我必须以某种方式区分从不同的xml文件加载的bean。

示例:两个扩展(让我们称之为A和B)安装了两个额外的弹簧文件:A.xml和B.xml。这两个文件都定义了相同Java类的bean。框架将此类的所有bean(使用自动装配)加载到某个工厂,然后在特定算法中使用此bean列表。但它应该能够知道bean的定义是什么扩展名。

当然我可以为bean添加额外的必需属性(例如扩展名的名称或代码),然后扩展开发人员必须为每个bean定义填充它,但这很容易出错:属性应该是对于某些特定扩展的所有bean都是相同的,而每个bean都填充它。我正在寻找一种更简洁的解决方案。

感谢。

2 个答案:

答案 0 :(得分:1)

听起来您的每个扩展都应该在自己的应用程序上下文中定义。这些上下文中的每一个都将共享一个父上下文,这将是您的应用程序“核心”。

这个shoulkd给你一个更容易的方法来了解哪个bean来自什么,因为你必须通过每个上下文来获得开始的bean。此外,通过在自己的上下文中隔离每个扩展,可以减少bean冲突的可能性。

答案 1 :(得分:1)

在单独的应用程序上下文中配置每个扩展。在每个应用程序上下文中,定义一个BeanPostProcessor,它将应用程序上下文定义的每个bean保存到将bean映射到应用程序上下文的注册表中。

配置应用程序上下文,该上下文将成为每个扩展应用程序上下文的父级。在此配置文件中,定义一个bean,它将bean名称映射到应用程序上下文标识符。

<!-- parent.xml -->
<beans>

  <bean
      id="beanNameToApplicationContextIdMap"
      class="java.util.HashMap"/>

</beans>

扩展应用程序上下文配置文件定义BeanNameToApplicationContextIdMapInserter的实例,它是实现BeanPostProcessor接口的自定义类。 applicationContextId属性配置为标识应用程序上下文的字符串。 map属性配置实例以更新父应用程序上下文中定义的映射。

<!-- alpha.xml -->
<beans>

  <bean class="com.example.BeanNameToApplicationContextIdMapInserter">
    <property name="applicationContextId" value="alpha"/>
    <property name="map" ref="beanNameToApplicationContextIdMap"/>
  </bean>

  <bean id="alphaService" class="...">
  </bean>

</beans>

BeanNameToApplicationContextIdMapInserter源代码:

public class BeanNameToApplicationContextIdMapInserter implements BeanPostProcessor {

    private String applicationContextId;
    private HashMap<String, String> map;

    public void setApplicationContextId(String id) {
        this.applicationContextId = id;
    }

    public void setMap(HashMap<String, String> map) {
        this.map = map;
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName)
        throws BeansException
    {
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
        throws BeansException
    {
        map.put(beanName, applicationContextId);
        return bean;
    }
}

您可以使用SingletonBeanFactoryLocator配置父应用程序上下文和每个扩展应用程序上下文。

<!-- beanRefFactory.xml -->
<beans>

  <bean
      id="parentApplicationContext"
      class="org.springframework.context.support.ClassPathXmlApplicationContext">
     <constructor-arg>
       <value>parent.xml</value>
     </constructor-arg>
  </bean>

  <bean
      id="alphaApplicationContext"
      class="org.springframework.context.support.ClassPathXmlApplicationContext">
     <constructor-arg>
       <value>alpha.xml</value>
     </constructor-arg>
     <constructor-arg>
       <ref bean="parentApplicationContext"/>
     </constructor-arg>
  </bean>

  <bean
      id="bravoApplicationContext"
      class="org.springframework.context.support.ClassPathXmlApplicationContext">
     <constructor-arg>
       <value>bravo.xml</value>
     </constructor-arg>
     <constructor-arg>
       <ref bean="parentApplicationContext"/>
     </constructor-arg>
  </bean>

</beans>

以下是将bean读取到应用程序上下文映射的示例代码。

public class Main {

    private static ApplicationContext getApplicationContext(String name) {
        BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
        BeanFactoryReference bfr = bfl.useBeanFactory(name);
        return (ApplicationContext) bfr.getFactory();
    }

    public static void main(String[] args) {
        ApplicationContext parentApplicationContext =
                getApplicationContext("parentApplicationContext");
        HashMap<String, String> map = (HashMap<String, String>)
                parentApplicationContext.getBean("beanNameToApplicationContextIdMap");

        System.out.println(map.get("alphaService"));

        System.out.println(map.get("bravoService"));
    }
}