2009-11-20 86 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() 
相關問題