如何在Spring XML上下文中实现有条件的资源导入?

我想实现的是“dynamic”(即基于configuration文件中定义的属性)启用/禁用导入子级Spring XML上下文的能力。

我想像这样的:

<import condition="some.property.name" resource="some-context.xml"/> 

在属性被parsing的地方(布尔型),当真正的时候导入上下文,否则不是。

到目前为止我的一些研究:

  • 编写一个自定义的NamespaceHandler(和相关的类),以便我可以在自己的名称空间中注册我自己的自定义元素。 例如: <myns:import condition="some.property.name" resource="some-context.xml"/>

    这种方法的问题是,我不想从Spring复制整个资源导入逻辑,我不明白我需要委托来做到这一点。

  • 重写DefaultBeanDefinitionDocumentReader以扩展“import”元素parsing和解释(这发生在importBeanDefinitionResource方法中)的行为。 但是我不确定在哪里可以注册这个扩展。

使用标准的Spring组件最接近你:

 <import resource="Whatever-${yyzzy}.xml"/> 

${xyzzy}从系统属性中插入一个属性。 (我使用上下文加载器类的hacky定制版本,在开始加载过程之前,将其他地方的属性添加到系统属性对象中。)

但是,你也可以逃避导入大量不必要的东西……并使用各种技巧来只实例化必要的bean。 这些技巧包括:

  • 占位符和物业替代
  • 使用新的Springexpression式语言select不同的bean,
  • 在目标名称中带有占位符的bean别名,
  • 懒豆初始化,和
  • 智能豆工厂。

使用Spring 3.1.x,可以使用beanconfiguration文件实现有条件的资源导入和bean实例化。 这当然是没有帮助,如果你使用的是早期的版本:)

为了logging,Robert Maldon解释了如何在这篇文章中完成bean的条件定义: http : //robertmaldon.blogspot.com/2007/04/conditionally-defining-spring-beans.html 。 在这里复制它是有点长(此外,我不认为我应该复制粘贴他的文章)。

采用这种方法的最终结果,适用于您的示例:

 <condbean:cond test="${some.property.name}"> <import resource="some-context.xml"/> </condbean:cond> 

这当然不像斯蒂芬C的解决scheme那么简单,但它更加强大。

如前所述,如果您使用的是Spring 3.1 +,则可以轻松地使用configuration文件来完成此操作

 <!-- default configuration - will be loaded if no profile is specified --> <!-- This will only work if it's put at the end of the configuration file --> <!-- so no bean definitions after that --> <beans profile="default"> <import resource="classpath:default.xml" /> </beans> <!-- some other profile --> <beans profile="otherProfile"> <import resource="classpath:other-profile.xml" /> </beans> 

otherProfile可以很容易地激活与例如

 mvn install -Dspring.profiles.active=otherProfile 

如果您在testing中使用不同的configuration文件,只需添加-DforkMode=never确保testing将在同一个虚拟机内运行,因此参数spring.profiles.active不会丢失

现在完全可以使用Spring 4了。

在你的主应用程序内容文件中

 <bean class="com.example.MyConditionalConfiguration"/> 

MyConditionalConfiguration看起来像

 @Configuration @Conditional(MyConditionalConfiguration.Condition.class) @ImportResource("/com/example/context-fragment.xml") public class MyConditionalConfiguration { static class Condition implements ConfigurationCondition { @Override public ConfigurationPhase getConfigurationPhase() { return ConfigurationPhase.PARSE_CONFIGURATION; } @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // only load context-fragment.xml if the system property is defined return System.getProperty("com.example.context-fragment") != null; } } } 

最后,你把你想要包含在/com/example/context-fragment.xml中的bean定义

查看@Conditional的JavaDoc

另一个select是让你的应用程序加载位于/ conf文件夹中的modules-config.xml文件,并在安装/configuration阶段对其进行编辑,以取消注释要加载的模块。

这是我使用的一个Web应用程序的解决scheme,作为不同集成模块的容器。 Web应用程序与所有不同的集成模块一起分发。 modules-config.xml放在tomcat的/ conf文件夹中,conf文件夹被添加到classpath(通过catalina.properties / common.loader属性)。 我的web应用webapp-config.xml有一个<import resource="classpath:/modules-config.xml"/>来加载它。

另一个要考虑的Spring 3.0:

  <alias name="Whatever" alias=""Whatever-${yyzzy}" /> 

${xyzzy}从系统属性中插入一个属性。