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

Java 如何在SpringXML上下文中实现条件资源导入?,java,xml,spring,Java,Xml,Spring,我想要实现的是,能够动态地(即基于配置文件中定义的属性)启用/禁用子Spring XML上下文的导入 我想象的是: <import condition="some.property.name" resource="some-context.xml"/> 属性解析为布尔值,如果为true,则导入上下文,否则不导入 到目前为止,我的一些研究: 编写自定义NamespaceHandler和相关类,以便在自己的命名空间中注册自己的自定义元素。例如:

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

我想象的是:

<import condition="some.property.name" resource="some-context.xml"/>
属性解析为布尔值,如果为true,则导入上下文,否则不导入

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

编写自定义NamespaceHandler和相关类,以便在自己的命名空间中注册自己的自定义元素。例如:

这种方法的问题是,我不想复制Spring的整个资源导入逻辑,而且我不清楚需要委托什么来完成这项工作

重写DefaultBeanDefinitionDocumentReader以扩展importBeanDefinitionResource方法中发生的导入元素解析和解释的行为。但是,我不确定在哪里可以注册此扩展


在Spring 4之前,使用标准弹簧组件可以获得的最接近的结果是:

<import resource="Whatever-${yyzzy}.xml"/>
其中${xyzy}从系统属性中插入属性。我使用了一个hacky自定义版本的context loader类,它在开始加载过程之前将其他位置的属性添加到system properties对象中

但是你也可以不进口很多不必要的东西。。。并使用各种技巧仅使必要的bean被实例化。这些技巧包括:

占位符和属性替换 使用新的Spring表达式语言选择不同的bean, 目标名称中带有占位符的bean别名, 惰性bean初始化,以及 智能豆工厂。
为了记录在案,Robert Maldon在本文中解释了如何完成bean的条件定义:。这是一个有点长的复制它在这里此外,我认为我不应该复制粘贴他的文章无论如何

此方法的最终结果(适用于您的示例)是:

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

它当然不像Stephen C的解决方案那么简单,但它更强大。

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

如前所述,如果您使用的是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>

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

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


这是我在web应用程序中使用的解决方案,它充当不同集成模块的容器。web应用程序分布在所有不同的集成模块中。modules-config.xml放在tomcat的/conf文件夹中,conf文件夹通过catalina.properties/common.loader属性添加到类路径中。我的Web应用程序WebApp-Fix.xml有一个加载它的程序。< /P> < P> > 3春季版:

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

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

现在完全可以使用Spring 4

在主应用程序内容文件中

<bean class="com.example.MyConditionalConfiguration"/>
最后,将希望包含的bean定义放入/com/example/context-fragment.xml中


请参见

您可以在自己的ContextLoaderListener中重写contextInitializedjavax.servlet.ServletContextEvent事件,并在调用super.contextInitializedevent之前设置所需的系统属性,如下所示

package com.mypackage;
import org.springframework.web.context.ContextLoaderListener;
public class MyContextLoaderListener extends ContextLoaderListener {
    public void contextInitialized(javax.servlet.ServletContextEvent event) {
        System.setProperty("xyz", "import-file-name.xml");
        super.contextInitialized(event);
    }
}
然后在web.xml中将ContextLoaderListener替换为MyContextLoaderListener

<listener>
    <listener-class>com.mypackage.MyContextLoaderListener</listener-class>
</listener>
现在您可以在spring.xml中使用

<import resource="${xyz}" /> 

我希望这会有所帮助。

与其进行条件导入,为什么不使用类路径扫描,只部署所需的配置?我发现条件导入更复杂,在查看已部署的应用程序时,更难确定哪些是/未配置的。如何定义所需的配置?我们有一些功能,它们被很好地模块化了,并且在白板模式加载上下文时自动激活。但我们需要一种动态读取的机制:在安装/配置时激活和停用这些功能。这是一种轻量级插件系统,我不想实际触及相关模块的上下文,并以这种方式阻止bean实例化。我真的希望保留模块的上下文边界,并在该级别上切换。我曾考虑过资源URI的属性替换程序,但正如您所说,只考虑系统属性,它只允许我切换到不同的上下文,而不是禁用一个上下文。也许我必须提供一个通用的、空的、禁用的模块context.xml?这只适用于系统属性。上下文占位符中的属性
导入时尚未加载@我知道。见我的第二句话。顺便说一句,这适用于2.5.5以后的版本。非常酷!谢谢你这么久之后的更新。很高兴他们终于为此做了些什么。我们这里也找不到占位符。只能使用System.property。原始问题仅涉及条件导入,不使用占位符。所以这实际上是正确的答案。配置文件很棒,但是调用其他一些条件实现怎么样?可能吗?
<listener>
    <listener-class>com.mypackage.MyContextLoaderListener</listener-class>
</listener>
<import resource="${xyz}" />