Accedere al file delle proprietà a livello di codice con Spring?


137

Usiamo il codice seguente per iniettare i bean Spring con le proprietà di un file delle proprietà.

<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 per accedere alle proprietà a livello di codice? Sto provando a fare un po 'di codice senza iniezione di dipendenza. Quindi mi piacerebbe avere solo un codice come questo:

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

Un esempio completo di accesso al file delle proprietà in primavera è al seguente link: bharatonjava.wordpress.com/2012/08/24/…

Risposte:


171

Che ne dici di PropertiesLoaderUtils ?

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

5
ecco una domanda, come è diverso dal mio, e ha altri due voti e pubblicato secondo ...
Zoidberg

3
Mi batte, non ho potuto votare :) Non userei un PropertyPlaceholderConfigurer, anche se è eccessivo per il compito.
Skaffman,

5
Stavo cercando di avvicinarmi il più possibile a ciò che aveva, sono stato votato in down-down così tante volte per non aver fornito dettagli sufficienti. In ogni caso, le tue risposte meritano i voti, poiché è corretto, immagino di essere solo geloso di non aver ottenuto anche 2 voti, LOL.
Zoidberg,

1
cosa dovremmo dare nel percorso se il file si trova in una directory esterna, diciamo cartella config?
prnjn

52

Se tutto ciò che vuoi fare è accedere al valore del segnaposto dal codice, c'è l' @Valueannotazione:

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

Per accedere ai segnaposto Da SPEL utilizzare questa sintassi:

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

Per esporre la configurazione a viste che hanno SPEL disattivato, è possibile utilizzare 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(); }
}

Quindi utilizzare l'espositore per esporre le proprietà a una vista:

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

Quindi, in vista, usa le proprietà esposte in questo modo:

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

Questa soluzione ha il vantaggio di poter fare affidamento sull'implementazione di segnaposto standard iniettata dal contesto: tag proprietà-segnaposto.

Ora, come nota finale, se hai davvero bisogno di un per catturare tutte le proprietà dei segnaposto e i loro valori, devi reindirizzarli attraverso StringValueResolver per assicurarti 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(); }
}

Grazie per questa risposta molto completa! c'è un modo per farlo con i campi finali?
Ward,

2
@WardC non puoi iniettare in un campo finale. Tuttavia, puoi inserire un argomento del costruttore e impostare un valore di campo finale all'interno del costruttore. Vedere stackoverflow.com/questions/2306078/... e stackoverflow.com/questions/4203302/...
Anttix

50

CREDITO : accesso programmatico alle proprietà in primavera senza rileggere il file delle proprietà

Ho trovato una buona implementazione dell'accesso alle proprietà a livello di codice in primavera senza ricaricare le stesse proprietà che Spring ha già caricato. [Inoltre, non è necessario codificare il percorso del file delle proprietà nell'origine]

Con queste modifiche, il codice appare più pulito e più gestibile.

Il concetto è piuttosto semplice. Basta estendere il segnaposto della proprietà predefinita di primavera (PropertyPlaceholderConfigurer) e acquisire le proprietà caricate 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();
    }

}

Esempio di utilizzo

SpringPropertiesUtil.getProperty("myProperty")

Modifiche alla configurazione della primavera

<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 risolvere i problemi che hai


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

1
Questa è la soluzione corretta Per rispondere alla 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 eclipse. Potresti anche essere in grado di avere una proprietà build. Questa soluzione presuppone che sia un po 'e dovrebbe affrontare questo, ma allo stesso tempo questa risposta è molto più lungo la linea della pratica standard per caricare le proprietà di primavera e java in un posto anziché separatamente. Un'altra opzione è quella di caricare un file delle proprietà generali con myFile nel file e utilizzarlo per ottenere il resto.
Rob,

1
Ho provato ad applicare questa soluzione alternativa al "nuovo" PropertySourcesPlaceholderConfigurer dalla primavera 3.1+, ma ho scoperto che il metodo processProperties (ConfigurableListableBeanFactory beanFactory, Proprietà props) ora è deprecato e quindi ora non è possibile accedere all'argomento "props". Osservando le fonti di PropertySourcesPlaceholderConfigurer non è possibile trovare un modo chiaro per esporre le proprietà. Qualche idea per farlo? Grazie!
Jorge Palacio,

48

L'ho fatto e ha funzionato.

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

Dovrebbe funzionare.


25

È inoltre possibile utilizzare i programmi di utilità Spring 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>

Quindi puoi ritirarli nella tua domanda con:

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

e usa anche queste proprietà nella tua 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


10

Crea una classe come 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 a un uso della proprietà

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

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

- scrivere getter e setter nella classe accessor

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

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

1
Di gran lunga la migliore risposta, dovrebbe solo autowire Environment.
Sbochins,

4

Come sapete, le versioni più recenti di Spring non usano PropertyPlaceholderConfigurer e ora usano un altro costrutto da incubo chiamato PropertySourcesPlaceholderConfigurer. Se stai cercando di ottenere proprietà risolte dal codice e desideri che il team di Spring ci abbia fornito un modo per farlo molto tempo fa, allora vota questo post! ... Perché è così che lo fai nel nuovo modo:

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

Per usarlo, assicurati di usare la tua sottoclasse nella tua @Configuration e salva un riferimento ad essa per un uso successivo.

@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;
    }
}

Uso:

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

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

2

Questo mi aiuta:

ApplicationContextUtils.getApplicationContext().getEnvironment()

In quale pacchetto è ApplicationContextUtils
Luca,

2

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

Puoi ottenere le tue proprietà attraverso la Environmentlezione. Come sta la documentazione:

Le proprietà svolgono un ruolo importante in quasi tutte le applicazioni e possono provenire da una varietà di fonti: file delle proprietà, proprietà del sistema JVM, variabili di ambiente del sistema, JNDI, parametri di contesto servlet, oggetti Proprietà ad hoc, Mappe e così via. Il ruolo dell'oggetto ambiente in relazione alle proprietà è di fornire all'utente una comoda interfaccia di servizio per la configurazione delle fonti di proprietà e la risoluzione delle proprietà da esse.

Avendo l'ambiente come envvariabile, chiama semplicemente:

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

È possibile ottenere le proprietà "non elaborate" tramite:

env.getProperty("your-property")

Cercherà tutte le fonti di proprietà che Spring ha registrato.

Puoi ottenere l'ambiente tramite:

  • iniettare ApplicationContext implementando ApplicationContextAwaree quindi chiamaregetEnvironment() il contesto
  • attuare EnvironmentAware.

È ottenuto attraverso l'implementazione di una classe perché le proprietà vengono risolte all'inizio dello start dell'applicazione, poiché potrebbero essere necessarie per la costruzione del bean.

Maggiori informazioni sulla documentazione: documentazione ambientale di primavera


1

Questo post spiega anche come accedere alle proprietà: http://maciej-miklas.blogspot.de/2013/07/spring-31-programmatic-access-to.html

È possibile accedere alle proprietà caricate dal segnaposto di proprietà di Spring su tale bean di primavera:

@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" />`

in servlet-context.xml dopo puoi usare direttamente il tuo file ovunque


0

Utilizzare il codice seguente nel file di configurazione di Spring per caricare il file dal percorso di classe dell'applicazione

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

0

Questo è il modo migliore per farlo funzionare:

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

Crea un'istanza della classe e chiama il metodo obj.getProperty ("my.property.name");
Daniel Almeida,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.