2009-11-20 90 views
109

我们使用下面的代码向属性文件中的属性注入Spring bean。用Spring以编程方式访问属性文件?

<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"); 
+0

性质春天访问文件中的一个完整的例子是在以下链接:http://bharatonjava.wordpress.com/2012/08/24/ access-properties-file-values-in-spring-mvc-controller-class/ – 2012-08-25 08:44:13

回答

139

PropertiesLoaderUtils怎么样?

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

这里是一个问题,这是怎样的不同于我的,并有两个票和第二张贴... – Zoidberg 2009-11-20 16:07:39

+3

打我,我没有去投票:)我不会使用'PropertyPlaceholderConfigurer',虽然它对于任务来说是过度的。 – skaffman 2009-11-20 16:15:12

+5

我试图尽可能地接近他所拥有的东西,因为没有提供足够的细节而被多次拒绝。在任何情况下,你的答案值得投票,因为它是正确的,我猜我只是嫉妒,我也没有得到2票,哈哈。 – Zoidberg 2009-11-20 17:07:58

42

我已经做到了这一点,它已经奏效。

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

这应该有效。

46

信用Programmatic access to properties in Spring without re-reading the properties file

我找到了一个很好的实现编程方式访问属性春季无需重新加载春天已经加载相同的属性。 [另外,不需要对源中的属性文件位置进行硬编码]

通过这些更改,代码看起来更清洁&可维护。

概念很简单。只是延长了弹簧的默认属性占位符(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") 

Spring配置改变

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

希望这有助于属性解决你的问题

+7

这不是一个完整的实现,将无法正常工作。 PropertyPlaceholderConfigurer使用PropertyPlaceholderHelper替换所有占位符属性,包括嵌套占位符。在Kalinga的实现中,如果你有类似myFile = $ {myFolder}/myFile的东西。txt,您将使用键“myFile”从地图获得的文字属性值为$ {myFolder}/myFile.txt。 – 2012-03-20 15:42:15

+0

帮助我的唯一解决方案。 – Denys 2014-02-10 13:07:32

+1

这是正确的解决方案。解决Brian的担忧。 $ {myFolder}应该是一个系统属性,不在属性文件中。这可以通过在eclipse中设置tomcat系统属性或运行属性来解决。你甚至可以有一个生成属性。这个解决方案假定有一点并且应该解决这个问题,但同时这个答案更符合标准实践的要求,以便在一个地方加载spring和java属性,而不是单独加载。另一种选择是在文件中加载一个带有myFile的常规属性文件,并使用它来获取剩余的文件。 – Rob 2014-12-23 15:22:23

43

如果所有你想要做的是从代码访问占位符值,有@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']} 

该解决方案,你可以依赖于上下文注入标准占位 实现的优点是:财产占位符标记。

现在作为最后一点,如果您确实需要捕获所有占位符属性及其值,则必须通过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(); } 
} 
+0

Thnx对于这个非常完整的答案!有没有办法与最终字段做到这一点? – Ward 2014-05-19 13:21:55

+1

@WardC您无法注入最终字段。但是,您可以注入构造函数参数并在构造函数中设置最终的字段值。见http://stackoverflow.com/questions/2306078/spring-constructor-injection-of-primitive-values-properties-with-annotation-b/2306468#2306468和http://stackoverflow.com/questions/4203302/how注入一个值到bean的构造函数使用注释 – anttix 2014-05-19 18:31:05

2

这是另一个示例。

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

您也可以使用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"/> 

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

1

这个帖子也explatis HOWTO访问属性:http://maciej-miklas.blogspot.de/2013/07/spring-31-programmatic-access-to.html

您可以访问由弹簧特性占位符在这样的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; 
    } 
} 
4

创建一类像下面

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"); 

- 写getter和setter的访问类

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

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

到目前为止最好的答案,应该只是autowire环境。 – sbochins 2015-09-11 22:49:37

2

这将解决任何嵌套的属性。

public class Environment extends PropertyPlaceholderConfigurer { 

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

/** 
* Iterate through all the Propery keys and build a Map, resolve all the nested values before beuilding 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 reterieved. 
* @return Value 
*/ 
public String getProperty(String name) { 
    return propertiesMap.get(name).toString(); 
} 
1

这帮助我:

ApplicationContextUtils.getApplicationContext().getEnvironment() 
相关问题