根据.properties文件中的属性导入Springconfiguration文件

在我的Spring xmlconfiguration中,我试图让这样的工作:

<beans> <import resource="${file.to.import}" /> <!-- Other bean definitions --> </beans> 

我想根据属性文件中的属性来决定要导入哪个文件。 我知道我可以使用System属性,但是我无法在启动时将属性添加到JVM。

注意:PropertyPlaceHolderConfigurer将不起作用。 在任何BeanFactoryPostProcessors运行之前,导入都被parsing。 导入元素只能parsingSystem.properties。

有没有人有一个简单的解决scheme呢? 我不想开始子类化框架类等…

谢谢

不幸的是,这比应该的要困难得多。 在我的应用程序中,我通过执行以下操作来完

  1. 一个小的“引导”上下文,负责加载一个PropertyPlaceholderConfigurer bean和另一个负责引导应用程序上下文的bean。

  2. 上面提到的第二个beaninput了要加载的“真正的”spring上下文文件。 我有我的spring上下文文件组织,使可configuration的部分是众所周知的,在同一个地方。 例如,我可能有3个configuration文件:one.onpremise.xml,one.hosted.xml,one.multitenant.xml。 这个bean以编程方式将这些上下文文件加载到当前的应用程序上下

这是有效的,因为上下文文件被指定为input负载它们的bean。 如果您只是尝试进行导入,就不会起作用,正如您所提到的那样,但这与稍微多一点的工作具有相同的效果。 引导类看起来像这样:

  public class Bootstrapper implements ApplicationContextAware, InitializingBean { private WebApplicationContext context; private String[] configLocations; private String[] testConfigLocations; private boolean loadTestConfigurations; public void setConfigLocations(final String[] configLocations) { this.configLocations = configLocations; } public void setTestConfigLocations(final String[] testConfigLocations) { this.testConfigLocations = testConfigLocations; } public void setLoadTestConfigurations(final boolean loadTestConfigurations) { this.loadTestConfigurations = loadTestConfigurations; } @Override public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { context = (WebApplicationContext) applicationContext; } @Override public void afterPropertiesSet() throws Exception { String[] configsToLoad = configLocations; if (loadTestConfigurations) { configsToLoad = new String[configLocations.length + testConfigLocations.length]; arraycopy(configLocations, 0, configsToLoad, 0, configLocations.length); arraycopy(testConfigLocations, 0, configsToLoad, configLocations.length, testConfigLocations.length); } context.setConfigLocations(configsToLoad); context.refresh(); } } 

基本上,获取应用程序上下文,设置其configuration位置,并告诉它自己刷新。 这在我的应用程序中完美工作。

希望这可以帮助。

对于Spring 2.5和3.0, 我有类似的解决scheme ,但是我刚刚阅读了关于3.1的即将发布的特性: 物业pipe理 ,这听起来也很棒。

Spring JIRA中存在一个老问题,那就是添加属性占位符对导入的支持(SPR-1358) ,这个问题被parsing为“不会修复”,但是现在已经有了一个使用EagerPropertyPlaceholderConfigurer的解决scheme。

我一直在游说SPR-1358重新开放,但目前还没有回应。 也许如果其他人将他们的用例添加到有助于提高认识的问题评论中。

为什么不:

  1. 在启动时阅读你的属性文件
  2. 这将决定加载哪个Springconfiguration
  3. 无论哪个Springconfiguration加载设置特定的东西, 然后加载一个普通的Springconfiguration

所以你正在有效地颠倒你目前提出的解决scheme。

添加类似于以下内容的内容:

 <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="ignoreResourceNotFound"><value>true</value></property> <property name="locations"> <list> <value>classpath:propertyfile.properties</value> </list> </property> </bean> 

如果您想要在applicationContext.xml之外指定导入的XML文件名,以便可以replaceapplicationContext.xml而不丢失导入的XML文件path的configuration,则可以添加一个中间Spring bean XML文件,例如confSelector。 xml,以便applicationContext.xml导入confSelector.xml,而confSelector.xml只包含引用合适的自定义Bean XML文件的<import>元素。

另一个可能使用的方法是XML实体(通过在XML起始处将<!ENTITY …>元素添加到DTD声明中定义)。 这些允许从其他文件导入XML片段,并为任何XML文件提供“属性占位符”function。

虽然这些解决scheme都不允许你拥有Java的.properties格式的configuration文件。

AndréSchuster的答案帮助我解决了一个非常类似的问题,我想根据我是在自己的主机上运行,​​由Jenkins在构build主机上运行还是在“真正”部署中来寻找属性的不同expression式。 我做到了这一点:

 <context:property-placeholder location="file:///etc/myplace/database.properties" /> 

后面跟着

 <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>WEB-INF/classes/resources/database.properties</value> ... </list> </property> </bean> 

这解决了我的问题,因为在我的开发主机上,我在/etc/myplace/database.properties中放了一个到database.properties的副本的链接,在运行Jenkins的服务器上稍微有点不同。 在真正的部署中,没有find这样的文件,所以Spring在我的class文件子目录中的资源中回退到“真实”文件。 如果有问题的属性已经被/etc/myplace/database.properties文件指定,那么(幸运的是)它们不会被本地文件重新定义。

不依赖系统属性的另一个解决方法是为每个文件使用不同的PropertyPlaceholderConfigurer加载所有文件的属性,并为每个文件定义不同的placeholderPrefix。 该占位符前缀由初始属性文件configuration。


定义第一个属性文件:(包含第一个或第二个)

global.properties

 fileToUse=first 

根据上面定义的属性定义包含可以切换的属性的文件:

first.properties

 aProperty=propertyContentOfFirst 

second.properties

 aProperty=propertyContentOfSecond 

然后定义所有文件的占位符:

 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:global.properties</value> </list> </property> </bean> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="placeholderPrefix" value="first{" /> <property name="locations"> <list> <value>classpath:first.properties</value> </list> </property> </bean> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="placeholderPrefix" value="second{" /> <property name="locations"> <list> <value>classpath:second.properties</value> </list> </property> </bean> 

使用global中定义的属性来标识要从另一个文件中使用的资源:

 ${fileToUse}{aProperty} 

如果我添加下面的JVM参数并且有文件myApplicationContext.dev.xml,那么spring会加载

-DmyEnvironment = dev的

 <context:property-placeholder /> <import resource="classpath:/resources/spring/myApplicationContext.${myEnvironment}.xml"/> 

我正在使用Spring 3并加载如下的属性:

 <context:property-placeholder location="/WEB-INF/my.properties" />