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

Bor*_*zic 55 java xml spring

我想要实现的是"动态"(即基于配置文件中定义的属性)启用/禁用子Spring XML上下文导入的能力.

我想象的是:

<import condition="some.property.name" resource="some-context.xml"/>
Run Code Online (Sandbox Code Playgroud)

解析属性的位置(布尔值)和true时导入上下文,否则不导入.

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

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

    这种方法的问题在于我不想从Spring复制整个资源导入逻辑,对我来说,我需要委派什么才能做到这一点.

  • 重写DefaultBeanDefinitionDocumentReader以扩展"import"元素解析和解释的行为(在importBeanDefinitionResource方法中发生).但是我不确定我可以在哪里注册此扩展程序.

Ste*_*n C 41

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

<import resource="Whatever-${yyzzy}.xml"/>
Run Code Online (Sandbox Code Playgroud)

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

但是你也可以通过导入大量不必要的东西来逃脱......并使用各种技巧只能导致必要的bean被实例化.这些技巧包括:

  • 占位符和财产替代
  • 使用新的Spring表达式语言选择不同的bean,
  • 目标名称中带有占位符的bean别名,
  • 懒惰的bean初始化,和
  • 智能豆工厂.

  • 这仅适用于系统属性.导入发生时,尚未加载上下文占位符的属性.(http://stackoverflow.com/questions/5253546/are-properties-read-by-a-spring-property-placeholder-immediately-available) (9认同)

pto*_*mli 24

现在,使用Spring 4完全可以实现.

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

<bean class="com.example.MyConditionalConfiguration"/>
Run Code Online (Sandbox Code Playgroud)

而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;
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,将所需的bean定义包含在/com/example/context-fragment.xml中

有关@Conditional的信息,请参阅JavaDoc


tea*_*bot 23

使用Spring 3.1.x,您可以使用bean配置文件来实现条件资源导入和bean实例化.如果您使用的是早期版本,这当然无济于事:)


Mar*_*vic 23

如前所述,如果您使用的是Spring 3.1+,则可以使用配置文件轻松完成

<!-- 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>
Run Code Online (Sandbox Code Playgroud)

otherProfile可以通过例如轻松激活

mvn install -Dspring.profiles.active=otherProfile
Run Code Online (Sandbox Code Playgroud)

如果你在测试中使用不同的配置文件,只需添加-DforkMode=never以确保测试将在同一个VM内运行,因此该参数spring.profiles.active不会丢失


esp*_*chi 20

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

根据您的示例,这种方法的最终结果是:

<condbean:cond test="${some.property.name}">
  <import resource="some-context.xml"/>
</condbean:cond>
Run Code Online (Sandbox Code Playgroud)

它肯定不像斯蒂芬C的解决方案那么简单,但它更强大.