2009-11-20 11 views
109

Utilizziamo il codice seguente per iniettare i bean Spring con le proprietà di un file delle proprietà.Accedi al file delle proprietà a livello di codice con 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> 

C'è un modo siamo in grado di accedere alle proprietà di programmazione? Sto cercando di fare un po 'di codice senza l'iniezione di dipendenza. Così mi piacerebbe avere solo alcuni codice come questo:

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

un esempio completo di accesso al file di proprietà in primavera è al seguente link: http://bharatonjava.wordpress.com/2012/08/24/ access-properties-file-values-in-spring-mvc-controller-class/ –

risposta

139

Che ne dici di PropertiesLoaderUtils?

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

ecco una domanda, com'è diverso dal mio, e ha altri due voti E postato secondo ... – Zoidberg

+3

Mi batte, non l'ho fatto arrivare a votare :) Non userei un 'PropertyPlaceholderConfigurer', anche se è eccessivo per l'attività. – skaffman

+5

Stavo cercando di avvicinarmi a ciò che aveva il più possibile, sono stato svalutato così tante volte per non aver fornito abbastanza dettagli. In ogni caso, le tue risposte meritano i voti, poiché è corretto, suppongo di essere solo geloso e non ho avuto anche 2 voti, LOL. – Zoidberg

42

ho fatto e ha funzionato.

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

Che dovrebbe funzionare.

46

CREDITO: Programmatic access to properties in Spring without re-reading the properties file

ho trovato una bella realizzazione di accedere alle proprietà di programmazione in primavera senza ricaricare le stesse proprietà che la primavera è già caricati. [Inoltre, non è richiesto per l'hardcoding il percorso del file delle proprietà nell'origine]

Con queste modifiche, il codice risulta più pulito & mantenibile.

Il concetto è piuttosto semplice. Basta estendere il segnaposto proprietà molla di default (PropertyPlaceholderConfigurer) e catturare le proprietà si carichi nella variabile locale

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

} 

Utilizzo Esempio

SpringPropertiesUtil.getProperty("myProperty") 

configurazione di Spring cambia

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

Spero che questo aiuti a risolvi il problema che hai

+7

Questa non è un'implementazione completa e non funzionerà correttamente. PropertyPlaceholderConfigurer utilizza un PropertyPlaceholderHelper per sostituire TUTTE le proprietà del segnaposto, inclusi i segnaposto nidificati. Nell'implementazione di Kalinga se hai qualcosa come myFile = $ {myFolder}/myFile.txt, il valore letterale della proprietà ottenuto dalla mappa utilizzando il tasto "myFile" sarà $ {myFolder} /myFile.txt. –

+0

L'unica soluzione che mi ha aiutato. – Denys

+1

Questa è la soluzione corretta. Per affrontare la preoccupazione di Brian. $ {MyFolder} dovrebbe essere una proprietà di sistema e non essere nel file delle proprietà. Questo può essere risolto avendo la proprietà di sistema tomcat o eseguendo la proprietà impostata in eclissi. Potresti anche essere in grado di avere una proprietà di costruzione. Questa soluzione presuppone che sia un po 'e che dovrebbe essere affrontata, ma allo stesso tempo questa risposta è molto più in linea con la pratica standard per caricare le proprietà spring e java in un unico posto invece che separatamente. Un'altra opzione è caricare un file di proprietà generale con myFile nel file e utilizzarlo per ottenere il resto. – Rob

43

Se tutto quello che vuoi fare è l'accesso valore segnaposto dal codice, v'è la @Value della nota:

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

Per accedere segnaposto Dall'uso SPEL questa sintassi:

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

per esporre la configurazione di punti di vista che hanno SPEL trasformato off, si può usare questo trucco:

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

e quindi utilizzare l'espositore per esporre oggetti da una visione:

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

Poi in vista, utilizzare le proprietà esposte in questo modo:

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

Questa soluzione ha il vantaggio che si può contare su implementazione standard segnaposto iniettata dal contesto: tag di proprietà-segnaposto.

Ora, come nota finale, se si ha realmente bisogno di un codice per catturare tutte le proprietà segnaposto e i relativi valori, è necessario eseguirne il pipe tramite StringValueResolver per assicurarsi che i segnaposto funzionino all'interno dei valori delle proprietà come previsto. Il seguente codice lo farà.

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 per questa risposta molto completa! c'è un modo per farlo con i campi finali? – Ward

+1

@WardC non è possibile inserire in un campo finale. Tuttavia, è possibile iniettare un argomento costruttore e impostare un valore finale del campo all'interno del costruttore. Vedi http://stackoverflow.com/questions/2306078/spring-constructor-injection-of-primitive-values-properties-with-annotation-b/2306468#2306468 e http://stackoverflow.com/questions/4203302/how -to-inject-a-value-to-bean-constructor-using-annotations – anttix

2

Ecco un altro esempio.

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

È anche possibile utilizzare i programmi di utilità primaverili o caricare le proprietà tramite PropertiesFactoryBean.

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

o:

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

Poi li si possono raccogliere nella vostra applicazione con:

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

e inoltre utilizzare queste proprietà nella configurazione:

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

Questo è anche nei documenti: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#xsd-config-body-schemas-util-properties

1

Questo post explatis anche proprietà access HOWTO: http://maciej-miklas.blogspot.de/2013/07/spring-31-programmatic-access-to.html

È possibile accedere alle proprietà caricate entro la primavera struttura a segnaposto su tale bean Spring:

@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

creare una classe come qui di seguito

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

     } 

    } 

Quindi, ovunque tu voglia accedere ad una proprietà, usa

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

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

- scrivere getter e setter nella classe di accesso

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

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

Di gran lunga la migliore risposta, dovrebbe solo autorizzare Ambiente. – sbochins

2

Questo risolverà tutte le proprietà nidificate.

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

Questo mi aiuta:

ApplicationContextUtils.getApplicationContext().getEnvironment() 
Problemi correlati