Java 区分从不同spring配置文件加载的bean

Java 区分从不同spring配置文件加载的bean,java,spring,Java,Spring,我们的项目基于SpringIOC,它提供了简单的可扩展性,这意味着我们的项目的功能通过我们所称的扩展(或插件)进行扩展,这些扩展提供了一些额外的SpringXML配置文件和新代码 问题是我必须以某种方式区分从不同xml文件加载的bean 示例:两个扩展(我们称之为A和B)安装了两个额外的spring文件:A.xml和B.xml。这两个文件都定义了相同Java类的bean。框架将这个类的所有bean(使用自动连接)加载到某个工厂,然后在特定算法中使用这个bean列表。但它应该能够知道bean是由什

我们的项目基于SpringIOC,它提供了简单的可扩展性,这意味着我们的项目的功能通过我们所称的扩展(或插件)进行扩展,这些扩展提供了一些额外的SpringXML配置文件和新代码

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

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

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


谢谢。

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


这将为您提供一种更简单的方法来了解哪个bean来自什么,因为您必须遍历每个上下文才能获得要开始使用的bean。另外,通过在各自的上下文中隔离每个扩展,可以减少bean冲突的可能性。

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

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

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

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

</beans>
BeanMatoApplicationContextIDMapInserter
源代码:

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;
    }
}
公共类BeanMatoApplicationContextIDMapinserter实现BeanPostProcessor{
私有字符串applicationContextId;
私有哈希映射;
public void setApplicationContextId(字符串id){
this.applicationContextId=id;
}
公共void setMap(HashMap映射){
this.map=map;
}
初始化前的公共对象后处理(对象bean、字符串bean名称)
抛出BeansException
{
返回豆;
}
公共对象后处理后初始化(对象bean、字符串bean名称)
抛出BeansException
{
map.put(beanName,applicationContextId);
返回豆;
}
}
您可以使用配置父应用程序上下文和每个扩展应用程序上下文

<!-- 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>
<!-- 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>

parent.xml
alpha.xml
bravo.xml
下面是将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"));
    }
}
公共类主{
私有静态应用程序上下文getApplicationContext(字符串名称){
BeanFactoryLocator bfl=SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bfr=bfl.useBeanFactory(名称);
返回(ApplicationContext)bfr.getFactory();
}
公共静态void main(字符串[]args){
应用程序上下文父应用程序上下文=
getApplicationContext(“parentApplicationContext”);
HashMap=(HashMap)
getBean(“beanNameToApplicationContextIdMap”);
System.out.println(map.get(“alphaService”);
System.out.println(map.get(“bravoService”);
}
}

谢谢。这听起来是个有趣的主意。但是我如何为每个配置文件分配一个新的上下文?现在如何识别和加载扩展配置文件?目前我只是使用正则表达式加载配置文件。例如,我正在加载product-*-config.xml文件,因此如果扩展部署了product-myextension-config.xml文件,那么它将被加载。似乎使用您建议的方法,我必须使命名约定更加严格,并分别预定义每个扩展名的配置文件名,以便能够在不同的上下文中加载它们。听起来很合理。我试试看,谢谢!在考虑了一下建议的方法后,我得出结论,我将无法从自动连接功能中获益——核心应用程序上下文中定义的工厂不会自动连接子应用程序上下文中定义的bean。这对我来说很不方便:-(谢谢,听起来很有趣,但是(就像上面的另一个答案一样):在考虑了一下建议的方法后,我得出结论,我将无法从自动连接功能中获益-核心应用程序上下文中定义的工厂不会自动连接子应用程序上下文中定义的bean。这对我来说非常不方便:-(