使用Spring以编程方式访问属性文件?


137

我们使用下面的代码从属性文件中注入具有属性的Spring bean。

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:/my.properties"/>
</bean>

<bean id="blah" class="abc">
    <property name="path" value="${the.path}"/>
</bean>

有没有一种方法可以通过编程方式访问属性?我试图做一些没有依赖注入的代码。所以我只想要一些这样的代码:

PropertyPlaceholderConfigurer props = new PropertyPlaceholderConfigurer();
props.load("classpath:/my.properties");
props.get("path");

访问属性文件中的弹簧的一个完整的例子是在以下链接:bharatonjava.wordpress.com/2012/08/24/...

Answers:


171

怎么样PropertiesLoaderUtils

Resource resource = new ClassPathResource("/my.properties");
Properties props = PropertiesLoaderUtils.loadProperties(resource);

5
这是一个问题,这与我的有什么不同,又有两票并发表在第二位...
Zoidberg,2009年

3
殴打我,我没有参加投票:)我不会使用PropertyPlaceholderConfigurer,尽管这对于完成任务而言过于严格。
skaffman

5
我试图尽可能地接近他所拥有的,我因没有提供足够的细节而被否决了很多次。无论如何,您的答案值得投票,因为它是正确的,我想我只是嫉妒,我也没有得到2票,大声笑。
Zoidberg

1
如果文件放在外部目录(例如config文件夹)中,我们应该在路径中给出什么?
prnjn

52

如果您要做的只是从代码访问占位符值,则有@Value注释:

@Value("${settings.some.property}")
String someValue;

要从SPEL访问占位符,请使用以下语法:

#('${settings.some.property}')

要将配置暴露给已关闭SPEL的视图,可以使用以下技巧:

package com.my.app;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class PropertyPlaceholderExposer implements Map<String, String>, BeanFactoryAware {  
    ConfigurableBeanFactory beanFactory; 

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = (ConfigurableBeanFactory) beanFactory;
    }

    protected String resolveProperty(String name) {
        String rv = beanFactory.resolveEmbeddedValue("${" + name + "}");

        return rv;
    }

    @Override
    public String get(Object key) {
        return resolveProperty(key.toString());
    }

    @Override
    public boolean containsKey(Object key) {
        try {
            resolveProperty(key.toString());
            return true;
        }
        catch(Exception e) {
            return false;
        }
    }

    @Override public boolean isEmpty() { return false; }
    @Override public Set<String> keySet() { throw new UnsupportedOperationException(); }
    @Override public Set<java.util.Map.Entry<String, String>> entrySet() { throw new UnsupportedOperationException(); }
    @Override public Collection<String> values() { throw new UnsupportedOperationException(); }
    @Override public int size() { throw new UnsupportedOperationException(); }
    @Override public boolean containsValue(Object value) { throw new UnsupportedOperationException(); }
    @Override public void clear() { throw new UnsupportedOperationException(); }
    @Override public String put(String key, String value) { throw new UnsupportedOperationException(); }
    @Override public String remove(Object key) { throw new UnsupportedOperationException(); }
    @Override public void putAll(Map<? extends String, ? extends String> t) { throw new UnsupportedOperationException(); }
}

然后使用暴露器将属性暴露给视图:

<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="tilesViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
    <property name="attributesMap">
        <map>
            <entry key="config">
                <bean class="com.my.app.PropertyPlaceholderExposer" />
            </entry>
        </map>
    </property>
</bean>

然后在视图中,使用如下所示的公开属性:

${config['settings.some.property']}

该解决方案的优势在于,您可以依靠context:property-placeholder标记注入的标准占位符实现。

现在作为最后的说明,如果您确实需要a来捕获所有占位符属性及其值,则必须通过StringValueResolver将它们传递给管道,以确保占位符按预期在属性值内起作用。以下代码将执行此操作。

package com.my.app;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.util.StringValueResolver;

public class AppConfig extends PropertyPlaceholderConfigurer implements Map<String, String> {

    Map<String, String> props = new HashMap<String, String>();

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
            throws BeansException {

        this.props.clear();
        for (Entry<Object, Object> e: props.entrySet())
            this.props.put(e.getKey().toString(), e.getValue().toString());

        super.processProperties(beanFactory, props);
    }

    @Override
    protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
            StringValueResolver valueResolver) {

        super.doProcessProperties(beanFactoryToProcess, valueResolver);

        for(Entry<String, String> e: props.entrySet())
            e.setValue(valueResolver.resolveStringValue(e.getValue()));
    }

    // Implement map interface to access stored properties
    @Override public Set<String> keySet() { return props.keySet(); }
    @Override public Set<java.util.Map.Entry<String, String>> entrySet() { return props.entrySet(); }
    @Override public Collection<String> values() { return props.values(); }
    @Override public int size() { return props.size(); }
    @Override public boolean isEmpty() { return props.isEmpty(); }
    @Override public boolean containsValue(Object value) { return props.containsValue(value); }
    @Override public boolean containsKey(Object key) { return props.containsKey(key); }
    @Override public String get(Object key) { return props.get(key); }
    @Override public void clear() { throw new UnsupportedOperationException(); }
    @Override public String put(String key, String value) { throw new UnsupportedOperationException(); }
    @Override public String remove(Object key) { throw new UnsupportedOperationException(); }
    @Override public void putAll(Map<? extends String, ? extends String> t) { throw new UnsupportedOperationException(); }
}

谢谢这个非常完整的答案!有没有办法对最终场做到这一点?
病房”

2
@WardC,您不能插入最终字段。但是,您可以注入构造函数参数,并在构造函数内部设置最终字段值。见stackoverflow.com/questions/2306078/...stackoverflow.com/questions/4203302/...
安克斯

50

CREDIT在Spring中以编程方式访问属性,而无需重新读取属性文件

我发现了一个很好的实现,可以在Spring中以编程方式访问属性,而无需重新加载Spring已经加载的相同属性。[此外,不需要在源文件中对属性文件的位置进行硬编码]

经过这些更改,代码看起来更清晰,更易于维护。

这个概念很简单。只需扩展spring默认属性占位符(PropertyPlaceholderConfigurer)并捕获它在局部变量中加载的属性

public class SpringPropertiesUtil extends PropertyPlaceholderConfigurer {

    private static Map<String, String> propertiesMap;
    // Default as in PropertyPlaceholderConfigurer
    private int springSystemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK;

    @Override
    public void setSystemPropertiesMode(int systemPropertiesMode) {
        super.setSystemPropertiesMode(systemPropertiesMode);
        springSystemPropertiesMode = systemPropertiesMode;
    }

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) throws BeansException {
        super.processProperties(beanFactory, props);

        propertiesMap = new HashMap<String, String>();
        for (Object key : props.keySet()) {
            String keyStr = key.toString();
            String valueStr = resolvePlaceholder(keyStr, props, springSystemPropertiesMode);
            propertiesMap.put(keyStr, valueStr);
        }
    }

    public static String getProperty(String name) {
        return propertiesMap.get(name).toString();
    }

}

使用范例

SpringPropertiesUtil.getProperty("myProperty")

春季配置变更

<bean id="placeholderConfigMM" class="SpringPropertiesUtil">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
    <property name="locations">
    <list>
        <value>classpath:myproperties.properties</value>
    </list>
    </property>
</bean>

希望这有助于解决您遇到的问题


8
这不是完整的实现,将无法正常工作。PropertyPlaceholderConfigurer使用PropertyPlaceholderHelper替换所有占位符属性,包括嵌套的占位符。在Kalinga的实现中,如果您具有myFile = $ {myFolder} /myFile.txt之类的内容,则使用键“ myFile”从地图中获取的文字属性值将为$ {myFolder} /myFile.txt。

1
这是正确的解决方案。为了解决Brian的担忧。$ {myFolder}应该是系统属性,而不是在属性文件中。这可以通过在Eclipse中设置tomcat系统属性或run属性来解决。您甚至可以拥有build属性。该解决方案假设有一点点并应解决,但与此同时,这个答案更多地是沿标准惯例将spring和java属性加载到一个地方而不是单独加载。另一种选择是使用文件中的myFile加载常规属性文件,然后使用其余文件来获取。
罗布2014年

1
我尝试将此解决方法应用于Spring 3.1+中的“新” PropertySourcesPlaceholderConfigurer,但是我发现现在不赞成使用processProperties(ConfigurableListableBeanFactory beanFactory,Properties props)方法,因此现在无法访问“ props”参数。在查看PropertySourcesPlaceholderConfigurer的源代码时,找不到找到属性的干净方法。有什么想法吗?谢谢!
豪尔赫·帕拉西奥

48

我做到了,它奏效了。

Properties props = PropertiesLoaderUtils.loadAllProperties("my.properties");
PropertyPlaceholderConfigurer props2 = new PropertyPlaceholderConfigurer();
props2.setProperties(props);

那应该工作。


25

您也可以使用spring utils,或通过PropertiesFactoryBean加载属性。

<util:properties id="myProps" location="classpath:com/foo/myprops.properties"/>

要么:

<bean id="myProps" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <property name="location" value="classpath:com/foo/myprops.properties"/>
</bean>

然后,您可以使用以下命令在您的应用程序中进行选择:

@Resource(name = "myProps")
private Properties myProps;

并在配置中另外使用这些属性:

<context:property-placeholder properties-ref="myProps"/>

这也在docs中:http : //docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#xsd-config-body-schemas-util-properties


10

创建一个如下所示的类

    package com.tmghealth.common.util;

    import java.util.Properties;

    import org.springframework.beans.BeansException;

    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

    import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

    import org.springframework.context.annotation.Configuration;

    import org.springframework.context.annotation.PropertySource;

    import org.springframework.stereotype.Component;


    @Component
    @Configuration
    @PropertySource(value = { "classpath:/spring/server-urls.properties" })
    public class PropertiesReader extends PropertyPlaceholderConfigurer {

        @Override
        protected void processProperties(
                ConfigurableListableBeanFactory beanFactory, Properties props)
                throws BeansException {
            super.processProperties(beanFactory, props);

        }

    }

然后,只要您要访问属性使用

    @Autowired
        private Environment environment;
    and getters and setters then access using 

    environment.getProperty(envName
                    + ".letter.fdi.letterdetails.restServiceUrl");

-在accessor类中编写getter和setter方法

    public Environment getEnvironment() {
            return environment;
        }`enter code here`

        public void setEnvironment(Environment environment) {
            this.environment = environment;
        }

1
到目前为止,最好的答案应该是自动连接环境。
sbochins 2015年

4

如您所知,较新版本的Spring不使用PropertyPlaceholderConfigurer,而是使用另一个称为PropertySourcesPlaceholderConfigurer的噩梦构造。如果您想从代码中获取可解析的属性,并希望Spring团队很久以前就给我们提供了一种方法,请对此文章投票!...因为这是新方法:

子类PropertySourcesPlaceholderConfigurer:

public class SpringPropertyExposer extends PropertySourcesPlaceholderConfigurer {

    private ConfigurableListableBeanFactory factory;

    /**
     * Save off the bean factory so we can use it later to resolve properties
     */
    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
            final ConfigurablePropertyResolver propertyResolver) throws BeansException {
        super.processProperties(beanFactoryToProcess, propertyResolver);

        if (beanFactoryToProcess.hasEmbeddedValueResolver()) {
            logger.debug("Value resolver exists.");
            factory = beanFactoryToProcess;
        }
        else {
            logger.error("No existing embedded value resolver.");
        }
    }

    public String getProperty(String name) {
        Object propertyValue = factory.resolveEmbeddedValue(this.placeholderPrefix + name + this.placeholderSuffix);
        return propertyValue.toString();
    }
}

要使用它,请确保在@Configuration中使用子类,并保存对它的引用以供以后使用。

@Configuration
@ComponentScan
public class PropertiesConfig {

    public static SpringPropertyExposer commonEnvConfig;

    @Bean(name="commonConfig")
    public static PropertySourcesPlaceholderConfigurer commonConfig() throws IOException {
        commonEnvConfig = new SpringPropertyExposer(); //This is a subclass of the return type.
        PropertiesFactoryBean commonConfig = new PropertiesFactoryBean();
        commonConfig.setLocation(new ClassPathResource("META-INF/spring/config.properties"));
        try {
            commonConfig.afterPropertiesSet();
        }
        catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
        commonEnvConfig.setProperties(commonConfig.getObject());
        return commonEnvConfig;
    }
}

用法:

Object value = PropertiesConfig.commonEnvConfig.getProperty("key.subkey");

2

这是另一个示例。

XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
cfg.postProcessBeanFactory(factory);


2

这将解决所有嵌套属性。

public class Environment extends PropertyPlaceholderConfigurer {

/**
 * Map that hold all the properties.
 */
private Map<String, String> propertiesMap; 

/**
 * Iterate through all the Property keys and build a Map, resolve all the nested values before building the map.
 */
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) throws BeansException {
    super.processProperties(beanFactory, props);

    propertiesMap = new HashMap<String, String>();
    for (Object key : props.keySet()) {
        String keyStr = key.toString();
        String valueStr = beanFactory.resolveEmbeddedValue(placeholderPrefix + keyStr.trim() + DEFAULT_PLACEHOLDER_SUFFIX);
        propertiesMap.put(keyStr, valueStr);
    }
} 

/**
 * This method gets the String value for a given String key for the property files.
 * 
 * @param name - Key for which the value needs to be retrieved.
 * @return Value
 */
public String getProperty(String name) {
    return propertiesMap.get(name).toString();
}

2

您可以通过Environment课程获取属性。就文档而言:

属性在几乎所有应用程序中都起着重要作用,并且可能源自多种来源:属性文件,JVM系统属性,系统环境变量,JNDI,Servlet上下文参数,临时属性对象,Map等。环境对象与属性有关的作用是为用户提供方便的服务界面,用于配置属性源并从中解析属性。

将环境作为env变量,只需调用:

env.resolvePlaceholders("${your-property:default-value}")

您可以通过以下方式获取“原始”属性:

env.getProperty("your-property")

它将搜索spring已注册的所有属性源。

您可以通过以下方式获取环境:

  • 通过实现注入ApplicationContext ApplicationContextAware然后调用getEnvironment()上下文
  • 实施EnvironmentAware

它是通过类的实现获得的,因为属性是在应用程序启动的早期阶段解析的,因为它们可能是bean构建所必需的。

阅读有关文档的更多信息:spring环境文档


1

这篇文章还介绍了如何访问属性:http ://maciej-miklas.blogspot.de/2013/07/spring-31-programmatic-access-to.html

您可以访问通过spring property-placeholder通过此类spring bean加载的属性:

@Named
public class PropertiesAccessor {

    private final AbstractBeanFactory beanFactory;

    private final Map<String,String> cache = new ConcurrentHashMap<>();

    @Inject
    protected PropertiesAccessor(AbstractBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public  String getProperty(String key) {
        if(cache.containsKey(key)){
            return cache.get(key);
        }

        String foundProp = null;
        try {
            foundProp = beanFactory.resolveEmbeddedValue("${" + key.trim() + "}");
            cache.put(key,foundProp);
        } catch (IllegalArgumentException ex) {
           // ok - property was not found
        }

        return foundProp;
    }
}

0
create .properties file in classpath of your project and add path configuration in xml`<context:property-placeholder location="classpath*:/*.properties" />`

之后,您可以在servlet-context.xml中直接在任何地方使用您的文件


0

请在您的spring配置文件中使用以下代码从应用程序的类路径加载文件

 <context:property-placeholder
    ignore-unresolvable="true" ignore-resource-not-found="false" location="classpath:property-file-name" />

0

这是我工作的最好方法:

package your.package;

import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

public class ApplicationProperties {

    private Properties properties;

    public ApplicationProperties() {
        // application.properties located at src/main/resource
        Resource resource = new ClassPathResource("/application.properties");
        try {
            this.properties = PropertiesLoaderUtils.loadProperties(resource);
        } catch (IOException ex) {
            Logger.getLogger(ApplicationProperties.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public String getProperty(String propertyName) {
        return this.properties.getProperty(propertyName);
    }
}

实例化类并调用方法obj.getProperty(“ my.property.name”);
丹尼尔·阿尔梅达
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.