使用 Spring 加载属性(通过系统属性)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2789511/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 04:04:02  来源:igfitidea点击:

Loading Properties with Spring (via System Properties)

springproperties

提问by n3utrino

My problem is as follows:

我的问题如下:

I have server.propertiesfor different environments. The path to those properties is provided trough a system property called propertyPath. How can I instruct my applicationContext.xmlto load the properties with the given propertyPathsystem property without some ugly MethodInvokingBeanwhich calls System.getProperty('');

我有server.properties不同的环境。这些属性的路径是通过一个名为 的系统属性提供的propertyPath。如何指示我applicationContext.xml使用给定的propertyPath系统属性加载属性而没有一些丑陋的MethodInvokingBean调用System.getProperty('');

My applicationContext.xml

我的 applicationContext.xml

<bean id="systemPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
        <property name="placeholderPrefix" value="sys{"/>
        <property name="properties">
            <props>
                <prop key="propertyPath">/default/path/to/server.properties</prop>
            </props>
        </property>
    </bean>


    <bean id="propertyResource" class="org.springframework.core.io.FileSystemResource" dependency-check="all" depends-on="systemPropertyConfigurer">
        <constructor-arg value="sys{propertyPath}"/>
    </bean>

    <bean id="serviceProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="location" ref="propertyResource"/>
    </bean>

    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" ref="propertyResource"/>
        <property name="placeholderPrefix" value="prop{"/>

        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <property name="ignoreResourceNotFound" value="false"/>
    </bean>

    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
         <property name="jndiName" value="prop{datasource.name}"/>
    </bean>

with this configuration the propertyResource alsways complains about

使用这种配置,propertyResource 总是抱怨

java.io.FileNotFoundException: sys{propertyPath} (The system cannot find the file specified)

Any suggestions? ;-) Thanks gabe

有什么建议?;-) 谢谢加布

EDIT:

编辑:

Now I debugged the loading process of the beans and it seems the setLocationMethod of the propertyConfigureris called before the systemPropertyConfigureris created so the propertyResource is initialized with "sys{propertyPath}". I played around with depends-onbut no luck.

现在我调试了bean的加载过程,似乎在创建之前调用了setLocation方法,因此propertyResource用“sys{propertyPath}”初始化。我玩过但没有运气。propertyConfigurersystemPropertyConfigurerdepends-on

采纳答案by n3utrino

Ok. I solved it. The problem is both of my PropertyPlaceholders are BeanFactoryPostProcessor those get processed after the context is loaded but the properties are set after. So it is impossible to populate one PropertyPlaceholder with another.

好的。我解决了。问题是我的两个 PropertyPlaceholders 都是 BeanFactoryPostProcessor 那些在加载上下文后被处理但属性是在之后设置的。所以不可能用另一个来填充一个 PropertyPlaceholder

Here is my solution in code ;-)

这是我的代码解决方案;-)

package property.util;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.Properties;

/**
 * ConfigurablePropertyPlaceholder takes instructions which SystemProperty
 * contains the path to the propertyfile to load.
 *
 * @author Gabe Kaelin
 * 
 */
public class ConfigurablePropertyPlaceholder extends PropertyPlaceholderConfigurer {


    private String propertyLocationSystemProperty;
    private String defaultPropertyFileName;


    public String getPropertyLocationSystemProperty() {
        return propertyLocationSystemProperty;
    }

    public void setPropertyLocationSystemProperty(String propertyLocationSystemProperty) {
        this.propertyLocationSystemProperty = propertyLocationSystemProperty;
    }

    public String getDefaultPropertyFileName() {
        return defaultPropertyFileName;
    }

    public void setDefaultPropertyFileName(String defaultPropertyFileName) {
        this.defaultPropertyFileName = defaultPropertyFileName;
    }

    /**
     * Overridden to fill the location with the path from the {@link #propertyLocationSystemProperty}
     *
     * @param props propeties instance to fill
     * @throws IOException
     */

    @Override
    protected void loadProperties(Properties props) throws IOException {
        Resource location = null;
        if(StringUtils.isNotEmpty(propertyLocationSystemProperty)){

            String propertyFilePath = System.getProperties().getProperty(propertyLocationSystemProperty);
            StringBuilder pathBuilder = new StringBuilder(propertyFilePath);

            if(StringUtils.isNotEmpty(defaultPropertyFileName) && !propertyFilePath.endsWith(defaultPropertyFileName)){
                pathBuilder.append("/").append(defaultPropertyFileName);
            }

            location = new FileSystemResource(pathBuilder.toString());
        }

        setLocation(location);
        super.loadProperties(props);
    }
}

The according applicationContext.xml entry

相应的 applicationContext.xml 条目

<bean id="propertyConfigurer" class="property.util.ConfigurablePropertyPlaceholder">
  <property name="propertyLocationSystemProperty" value="propertyPath" />
  <property name="defaultPropertyFileName" value="server.properties" />
  <property name="ignoreResourceNotFound" value="false"/>
</bean>

the java process can be started with

java进程可以用

java -DpropertyPath=/path/to/properties

and it loads the properties and they are available in the applicationContext.xml

并加载属性,它们在 applicationContext.xml 中可用

回答by Renato Del Gaudio

The solution given to extend PropertyPlaceholderConfigurer seems ok but it should also work relying on the standard org.springframework.beans.factory.config.PropertiesFactoryBean implementation without writing any additional code.

扩展 PropertyPlaceholderConfigurer 的解决方案似乎没问题,但它也应该依赖于标准的 org.springframework.beans.factory.config.PropertiesFactoryBean 实现而无需编写任何额外的代码。

Simply use the variable reference that will be resolved by Spring.

只需使用将由 Spring 解析的变量引用。

e.g.

例如

Configure spring as follows:

配置spring如下:

<bean id="configProp"
      class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="locations">
        <list>
            <value>file:${propertyPath}</value>
        </list>
    </property>
</bean>

Once you invoke Java with the env variable (propertyPath), Spring will resolve it, load the property file and inject it into the application context

一旦您使用 env 变量(propertyPath)调用 Java,Spring 将解析它,加载属性文件并将其注入到应用程序上下文中

java -DpropertyPath=/path/to/properties

java -DpropertyPath=/path/to/properties

回答by Bozho

You have two options:

您有两个选择:

  • use sys:as prefix (and hence sys:propertyPath)

  • set the placeholderSuffixproperty of the placeholder configurer to }, so that you can access the properties with sys{prop}. If you omit this property, you will have to use sys{prop

  • 使用sys:前缀(因此sys:propertyPath

  • placeholderSuffix占位符配置器的属性设置为},以便您可以使用sys{prop}. 如果省略此属性,则必须使用sys{prop