根据.properties文件中的属性导入Spring配置文件

时间:2009-10-05 13:24:47

标签: java spring configuration

在我的Spring xml配置中,我试图让这样的东西起作用:

<beans>

   <import resource="${file.to.import}" />

   <!-- Other bean definitions -->

</beans>

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

注意:PropertyPlaceHolderConfigurer将工作。在运行任何BeanFactoryPostProcessor之前解析导入。 import元素只能解析System.properties。

有没有人有这个简单的解决方案?我不想开始子类化框架类等等......

由于

10 个答案:

答案 0 :(得分:15)

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

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

  2. 上面提到的第二个bean将要加载的“真实”spring上下文文件作为输入。我将弹簧上下文文件组织起来,以便可配置部分在同一个地方是众所周知的。例如,我可能有3个配置文件:one.onpremise.xml,one.hosted.xml,one.multitenant.xml。 bean以编程方式将这些上下文文件加载到当前应用程序上下文中。

  3. 这是有效的,因为上下文文件被指定为负责加载它们的bean的输入。如果你只是尝试进行导入,它将无法工作,正如你所提到的,但这会产生相同的效果,稍微多一些工作。 bootstrap类看起来像这样:

     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();
        }
    }
    

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

    希望这有帮助。

答案 1 :(得分:6)

对于Spring 2.5和3.0,I have a similar solution到路易斯,但我刚刚读到3.1即将发布的功能:property management,这听起来也很棒。

答案 2 :(得分:5)

Spring JIRA上存在一个旧问题,即添加properties placeholder support for import (SPR-1358)已被解析为“无法修复”,但此后一直是使用EagerPropertyPlaceholderConfigurer提出的解决方案。

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

答案 3 :(得分:2)

为什么不:

  1. 在启动时阅读您的属性文件
  2. 将决定加载哪个Spring配置
  3. 无论加载哪个Spring配置设置特定的东西,然后加载一个公共的Spring配置
  4. 因此,您可以有效地反转当前提出的解决方案。

答案 4 :(得分:1)

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

<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>

答案 5 :(得分:1)

如果你想要的是在applicationContext.xml之外指定导入的XML文件名,这样你就可以替换applicationContext.xml而不会丢失导入的XML文件路径的配置,你可以添加一个中间的Spring bean XML文件,比如说,confSelector.xml,以便applicationContext.xml导入confSelector.xml,而confSelector.xml只包含一个&lt; import&gt;引用合适的自定义bean XML文件的元素。

另一种可能有用的方法是XML实体(通过在XML开头的DTD声明中添加&lt;!ENTITY ...&gt;元素来定义)。这些允许从其他文件导入XML片段,并为任何XML文件提供类似“属性占位符”的功能。

但这些解决方案都不允许您使用Java的.properties格式配置文件。

答案 6 :(得分:0)

AndréSchuster的答案,我碰到了,帮助我解决了一个非常类似的问题,我想要找到一个不同的属性表达式取决于我是在我自己的主机上运行,​​Jenkins在我们的构建主机上还是在“真正的“部署。我这样做了:

<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的服务器上略有不同。在实际部署中,没有找到这样的文件,因此Spring回退到我的类文件子目录中 resources 中的“真实”文件。如果有关的属性已由 /etc/myplace/database.properties 上的文件指定,那么(幸运的是)它们不会被本地文件重新定义。

答案 7 :(得分:0)

不依赖于系统属性的另一种解决方法是使用不同的PropertyPlaceholderConfigurer为每个文件加载所有文件的属性,并为每个文件定义不同的placeholderPrefix。 该placeholderprefix由初始属性文件配置。



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

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}

答案 8 :(得分:0)

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

-DmyEnvironment = dev的

<context:property-placeholder />

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

答案 9 :(得分:-2)

我正在使用Spring 3并加载类似的属性:

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