Programmgesteuert mit Spring auf die Eigenschaftendatei zugreifen?

137

Wir verwenden den folgenden Code, um Spring Beans Eigenschaften aus einer Eigenschaftendatei zu injizieren.

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

Gibt es eine Möglichkeit, programmgesteuert auf die Eigenschaften zuzugreifen? Ich versuche, Code ohne Abhängigkeitsinjektion zu erstellen. Ich möchte also nur einen Code wie diesen haben:

PropertyPlaceholderConfigurer props = new PropertyPlaceholderConfigurer();
props.load("classpath:/my.properties");
props.get("path");
Marcus Leon
quelle
Ein vollständiges Beispiel für den Zugriff auf die Eigenschaftendatei im Frühjahr finden Sie unter folgendem Link: bharatonjava.wordpress.com/2012/08/24/…

Antworten:

171

Wie wäre es mit PropertiesLoaderUtils ?

Resource resource = new ClassPathResource("/my.properties");
Properties props = PropertiesLoaderUtils.loadProperties(resource);
Skaffman
quelle
5
Hier ist eine Frage, wie unterscheidet sich das von meiner und hat zwei weitere Stimmen und hat den zweiten gepostet ...
Zoidberg
3
Schlägt mich, ich konnte nicht wählen :) Ich würde kein verwenden PropertyPlaceholderConfigurer, obwohl es für die Aufgabe übertrieben ist.
Skaffman
5
Ich habe versucht, so nah wie möglich an das heranzukommen, was er hatte. Ich wurde so oft herabgestimmt, weil ich nicht genug Details geliefert habe. Auf jeden Fall verdienen Ihre Antworten die Stimmen, da es richtig ist, ich denke, ich bin nur eifersüchtig, dass ich nicht auch 2 Stimmen bekommen habe, LOL.
Zoidberg
1
Was sollen wir im Pfad angeben, wenn die Datei in einem externen Verzeichnis abgelegt wird, sagen wir Konfigurationsordner?
Prnjn
52

Wenn Sie nur über den Code auf den Platzhalterwert zugreifen möchten, gibt es die @ValueAnmerkung:

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

So greifen Sie über SPEL auf Platzhalter zu: Verwenden Sie diese Syntax:

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

Verwenden Sie diesen Trick, um die Konfiguration für Ansichten bereitzustellen, bei denen SPEL deaktiviert ist:

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

Verwenden Sie dann den Exposer, um Eigenschaften für eine Ansicht verfügbar zu machen:

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

Verwenden Sie dann in der Ansicht die belichteten Eigenschaften wie folgt:

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

Diese Lösung hat den Vorteil, dass Sie sich auf die Standardimplementierung von Platzhaltern verlassen können, die durch den Kontext eingefügt wird: Eigenschaft-Platzhalter-Tag.

Wenn Sie abschließend wirklich alle Platzhalter-Eigenschaften und ihre Werte erfassen möchten, müssen Sie sie über StringValueResolver leiten, um sicherzustellen, dass Platzhalter wie erwartet innerhalb der Eigenschaftswerte funktionieren. Der folgende Code wird das tun.

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(); }
}
Anttix
quelle
Vielen Dank für diese sehr vollständige Antwort! Gibt es eine Möglichkeit, dies mit endgültigen Feldern zu tun?
Ward
2
@WardC Sie können nicht in ein letztes Feld injizieren. Sie können jedoch in ein Konstruktorargument einfügen und einen endgültigen Feldwert im Konstruktor festlegen. Siehe stackoverflow.com/questions/2306078/… und stackoverflow.com/questions/4203302/…
Anttix
50

CREDIT : Programmatischer Zugriff auf Eigenschaften in Spring, ohne die Eigenschaftendatei erneut zu lesen

Ich habe eine gute Implementierung gefunden, um im Frühjahr programmgesteuert auf die Eigenschaften zuzugreifen, ohne die gleichen Eigenschaften neu zu laden, die der Frühling bereits geladen hat. [Außerdem ist es nicht erforderlich, den Speicherort der Eigenschaftendatei in der Quelle fest zu codieren.]

Mit diesen Änderungen sieht der Code sauberer und wartbarer aus.

Das Konzept ist ziemlich einfach. Erweitern Sie einfach den Platzhalter für die Spring-Standardeigenschaft (PropertyPlaceholderConfigurer) und erfassen Sie die Eigenschaften, die in die lokale Variable geladen werden

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

}

Anwendungsbeispiel

SpringPropertiesUtil.getProperty("myProperty")

Änderungen der Federkonfiguration

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

Hoffe, dies hilft, die Probleme zu lösen, die Sie haben

Ashok Koyi
quelle
8
Dies ist keine vollständige Implementierung und funktioniert nicht richtig. Der PropertyPlaceholderConfigurer verwendet einen PropertyPlaceholderHelper, um ALLE Platzhalteigenschaften, einschließlich verschachtelter Platzhalter, zu ersetzen. Wenn Sie in Kalingas Implementierung so etwas wie myFile = $ {myFolder} /myFile.txt haben, lautet der Literal-Eigenschaftswert, den Sie mit dem Schlüssel "myFile" aus der Karte erhalten, $ {myFolder} /myFile.txt.
1
Dies ist die richtige Lösung. Um Brians Besorgnis anzusprechen. Der $ {myFolder} sollte eine Systemeigenschaft sein und nicht in der Eigenschaftendatei enthalten sein. Dies kann gelöst werden, indem die Tomcat-Systemeigenschaft oder die run-Eigenschaft in Eclipse festgelegt werden. Möglicherweise können Sie sogar eine Build-Eigenschaft haben. Diese Lösung geht davon aus, dass ein wenig und sollte dies ansprechen, aber gleichzeitig entspricht diese Antwort viel mehr der Standardpraxis, Feder- und Java-Eigenschaften an einem Ort anstatt separat zu laden. Eine andere Möglichkeit besteht darin, eine allgemeine Eigenschaftendatei mit myFile in die Datei zu laden und diese zu verwenden, um den Rest abzurufen.
Rob
1
Ich habe versucht, diese Problemumgehung auf den 'neuen' PropertySourcesPlaceholderConfigurer ab Spring 3.1+ anzuwenden, aber ich habe festgestellt, dass die Methode processProperties (ConfigurableListableBeanFactory beanFactory, Eigenschaften-Requisiten) jetzt veraltet ist und daher jetzt kein Zugriff auf das Argument 'Requisiten' besteht. Wenn Sie sich die Quellen von PropertySourcesPlaceholderConfigurer ansehen, können Sie keine saubere Möglichkeit finden, die Eigenschaften verfügbar zu machen. Irgendwelche Ideen dazu? Vielen Dank!
Jorge Palacio
48

Ich habe das getan und es hat funktioniert.

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

Das sollte funktionieren.

Zoidberg
quelle
25

Sie können auch entweder die Spring Utils verwenden oder Eigenschaften über die PropertiesFactoryBean laden.

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

oder:

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

Dann können Sie sie in Ihrer Bewerbung abholen mit:

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

und verwenden Sie zusätzlich diese Eigenschaften in Ihrer Konfiguration:

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

Dies steht auch in den Dokumenten: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#xsd-config-body-schemas-util-properties

enkor
quelle
10

Erstellen Sie eine Klasse wie unten

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

        }

    }

Dann, wo immer Sie auf eine Immobilie zugreifen möchten

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

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

- Schreiben Sie Getter und Setter in die Accessor-Klasse

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

        public void setEnvironment(Environment environment) {
            this.environment = environment;
        }
user1419261
quelle
1
Bei weitem die beste Antwort, sollte nur Autowire Environment.
Sbochins
4

Wie Sie wissen, verwenden die neueren Versionen von Spring den PropertyPlaceholderConfigurer nicht und verwenden jetzt ein anderes albtraumhaftes Konstrukt namens PropertySourcesPlaceholderConfigurer. Wenn Sie versuchen, aufgelöste Eigenschaften aus Code zu erhalten, und möchten, dass das Spring-Team uns vor langer Zeit eine Möglichkeit dazu gegeben hat, stimmen Sie diesen Beitrag ab! ... weil du es so machst:

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

Stellen Sie zur Verwendung sicher, dass Sie Ihre Unterklasse in Ihrer @Configuration verwenden, und speichern Sie einen Verweis darauf für die spätere Verwendung.

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

Verwendung:

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

Hier ist ein weiteres Beispiel.

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

Das hilft mir:

ApplicationContextUtils.getApplicationContext().getEnvironment()
Ruzal Yumaev
quelle
Welches Paket ist ApplicationContextUtils in
Luke
2

Dadurch werden alle verschachtelten Eigenschaften aufgelöst.

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

Sie können Ihre Eigenschaften durch EnvironmentKlasse erhalten. Wie die Dokumentation steht:

Eigenschaften spielen in fast allen Anwendungen eine wichtige Rolle und können aus verschiedenen Quellen stammen: Eigenschaftendateien, JVM-Systemeigenschaften, Systemumgebungsvariablen, JNDI, Servlet-Kontextparameter, Ad-hoc-Eigenschaftenobjekte, Maps usw. Die Rolle des Umgebungsobjekts in Bezug auf Eigenschaften besteht darin, dem Benutzer eine bequeme Serviceschnittstelle zum Konfigurieren von Eigenschaftsquellen und zum Auflösen von Eigenschaften daraus bereitzustellen.

Wenn Sie Environment als envVariable haben, rufen Sie einfach Folgendes auf:

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

Sie können Ihre "rohen" Eigenschaften erhalten durch:

env.getProperty("your-property")

Es werden alle Eigenschaftenquellen durchsucht, die der Frühling registriert hat.

Sie können die Umgebung entweder erhalten über:

  • Injizieren Sie ApplicationContext, indem Sie implementieren ApplicationContextAwareund dann aufrufengetEnvironment() Kontext auf
  • implementieren EnvironmentAware.

Dies wird durch die Implementierung einer Klasse erreicht, da Eigenschaften in einem frühen Stadium des Anwendungsstarts aufgelöst werden, da sie möglicherweise für die Bean-Konstruktion erforderlich sind.

Lesen Sie mehr zur Dokumentation: spring Umgebungsdokumentation

Augustin Ghauratto
quelle
1

In diesem Beitrag wird auch erläutert, wie Sie auf Eigenschaften zugreifen können: http://maciej-miklas.blogspot.de/2013/07/spring-31-programmatic-access-to.html

Sie können auf Eigenschaften zugreifen, die von spring property-placeholder über eine solche Spring Bean geladen wurden:

@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;
    }
}
Maciej Miklas
quelle
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 danach können Sie Ihre Datei überall direkt verwenden

Aniket
quelle
0

Verwenden Sie den folgenden Code in Ihrer Spring-Konfigurationsdatei, um die Datei aus dem Klassenpfad Ihrer Anwendung zu laden

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

Dies ist der beste Weg, wie ich es zum Laufen gebracht habe:

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);
    }
}
Daniel Almeida
quelle
Instanziieren Sie die Klasse und rufen Sie die Methode obj.getProperty ("my.property.name") auf.
Daniel Almeida