我们的项目基于Spring IoC,它提供了轻松的可扩展性,这意味着我们的项目功能通过我们称之为扩展(或插件)的扩展来扩展,这些扩展提供了一些额外的Spring xml配置文件+新代码。
问题是我必须以某种方式区分从不同的xml文件加载的bean。
示例:两个扩展(让我们称之为A和B)安装了两个额外的弹簧文件:A.xml和B.xml。这两个文件都定义了相同Java类的bean。框架将此类的所有bean(使用自动装配)加载到某个工厂,然后在特定算法中使用此bean列表。但它应该能够知道bean的定义是什么扩展名。
当然我可以为bean添加额外的必需属性(例如扩展名的名称或代码),然后扩展开发人员必须为每个bean定义填充它,但这很容易出错:属性应该是对于某些特定扩展的所有bean都是相同的,而每个bean都填充它。我正在寻找一种更简洁的解决方案。
感谢。
答案 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"));
}
}