Spring Boot und mehrere externe Konfigurationsdateien

125

Ich habe mehrere Eigenschaftendateien, die ich aus dem Klassenpfad laden möchte. Es gibt einen Standardsatz, unter /src/main/resourcesdem ein Teil von ist myapp.jar. Ich springcontexterwarte, dass sich Dateien im Klassenpfad befinden. dh

<util:properties id="Job1Props"
    location="classpath:job1.properties"></util:properties>

<util:properties id="Job2Props"
    location="classpath:job2.properties"></util:properties>

Ich brauche auch die Option, um diese Eigenschaften mit einem externen Satz zu überschreiben. Ich habe einen externen Konfigurationsordner in cwd. Gemäß Spring Boot sollte sich der Konfigurationsordner im Klassenpfad befinden. Aus dem Dokument ist jedoch nicht ersichtlich, ob nur die applicaiton.propertiesvon dort oder alle Eigenschaften in der Konfiguration überschrieben werden .

Wenn ich es getestet habe, wird es nur application.propertiesabgeholt und der Rest der Immobilien wird noch abgeholt /src/main/resources. Ich habe versucht, sie als durch Kommas getrennte Liste anzugeben, spring.config.locationaber der Standardsatz wird immer noch nicht überschrieben.

Wie kann ich dafür sorgen, dass mehrere externe Konfigurationsdateien die Standarddateien überschreiben?

Als Problemumgehung habe ich derzeit app.config.location(app-spezifische Eigenschaft) verwendet, die ich über die Befehlszeile bereitstelle. dh

java -jar myapp.jar app.config.location=file:./config

und ich änderte meine applicationcontextzu

<util:properties id="Job2Props"
    location="{app.config.location}/job2.properties"></util:properties>

Und so trenne ich beim Laden von Application zwischen Datei und Klassenpfad.
EDITS:

//psuedo code

if (StringUtils.isBlank(app.config.location)) {
            System.setProperty(APP_CONFIG_LOCATION, "classpath:");
}

Ich möchte die obige Problemumgehung wirklich nicht verwenden und alle externen Konfigurationsdateien im Klassenpfad wie bei der application.propertiesDatei durch Spring überschreiben lassen .

nir
quelle
4
Das application.propertieswird immer geladen, wobei spring.config.locationSie zusätzliche Konfigurationsspeicherorte hinzufügen können, die auf Dateien überprüft werden (dh wenn es mit a endet /). Wenn Sie dort jedoch eine durch Kommas getrennte Liste einfügen, die auf Dateien verweist, die geladen werden. Dies wird auch im Spring Boot Referenzhandbuch hier erklärt
M. Deinum

Antworten:

154

Bei Verwendung von Spring Boot werden die Eigenschaften in der folgenden Reihenfolge geladen (siehe Externalisierte Konfiguration im Spring Boot-Referenzhandbuch).

  1. Kommandozeilenargumente.
  2. Java-Systemeigenschaften (System.getProperties ()).
  3. Betriebssystemumgebungsvariablen.
  4. JNDI-Attribute aus Java: comp / env
  5. Eine RandomValuePropertySource, die nur zufällige Eigenschaften hat. *.
  6. Anwendungseigenschaften außerhalb Ihres verpackten JARs (application.properties einschließlich YAML- und Profilvarianten).
  7. In Ihrem JAR verpackte Anwendungseigenschaften (application.properties einschließlich YAML- und Profilvarianten).
  8. @ PropertySource-Anmerkungen zu Ihren @ Configuration-Klassen.
  9. Standardeigenschaften (angegeben mit SpringApplication.setDefaultProperties).

Beim Auflösen von Eigenschaften (dh das @Value("${myprop}")Auflösen erfolgt in umgekehrter Reihenfolge (also beginnend mit 9).

Um verschiedene Dateien hinzuzufügen, können Sie die spring.config.locationEigenschaften verwenden, die eine durch Kommas getrennte Liste von Eigenschaftendateien oder Dateispeicherorten (Verzeichnissen) enthalten.

-Dspring.config.location=your/config/dir/

Das obige fügt ein Verzeichnis hinzu, das nach application.propertiesDateien durchsucht wird.

-Dspring.config.location=classpath:job1.properties,classpath:job2.properties

Dadurch werden die 2 Eigenschaftendateien zu den geladenen Dateien hinzugefügt.

Die Standardkonfigurationsdateien und -speicherorte werden vor den zusätzlich angegebenen geladen spring.config.location, was bedeutet, dass letztere die in den vorherigen festgelegten Eigenschaften immer überschreiben. (Siehe auch diesen Abschnitt des Spring Boot-Referenzhandbuchs).

Wenn sie spring.config.locationVerzeichnisse enthalten (im Gegensatz zu Dateien), sollten sie mit / enden (und werden mit den Namen angehängt, die spring.config.namevor dem Laden generiert wurden). Der Standardsuchpfad classpath:,classpath:/config,file:,file:config/wird immer verwendet, unabhängig vom Wert von spring.config.location. Auf diese Weise können Sie Standardwerte für Ihre Anwendung in application.properties(oder einen anderen von Ihnen gewählten Basisnamen spring.config.name) einrichten und diese zur Laufzeit mit einer anderen Datei überschreiben, wobei die Standardeinstellungen beibehalten werden.

UPDATE: Da das Verhalten von spring.config.location jetzt den Standard überschreibt, anstatt ihn hinzuzufügen. Sie müssen spring.config.additional-location verwenden, um die Standardeinstellungen beizubehalten. Dies ist eine Verhaltensänderung von 1.x auf 2.x.

M. Deinum
quelle
2
Vielen Dank, aber ich habe dieses Referenzdokument bereits gelesen und das Folgende ist für mich verwirrend. "-Dspring.config.location = your / config / dir / Das obige fügt ein Verzeichnis hinzu, das für application.properties-Dateien konsultiert wird." Was bedeutet das für application.properties-Dateien? Das ist nur eine Datei. In jedem Fall, wenn es in der Lage ist, das gesamte Verzeichnis mit "/" am Ende aufzunehmen, muss ich nicht jedes als durch Kommas getrennte Liste angeben. Ich glaube, ich habe beide Ansätze ausprobiert, wie ich in meinem Beitrag erwähnt habe, aber ich werde es noch einmal versuchen
Uhr
Wie im Dokument angegeben, wird die Auswahl wie die anderen Standardspeicherorte für das application.propertiesund konsultiert application-[env].properties. Andere Eigenschaftendateien werden nicht berücksichtigt. Dies wird auch im Referenzhandbuch angegeben (im Abschnitt, zu dem der Link führt, und im Zitat aus dem Referenzhandbuch).
M. Deinum
1
Ja, aber das macht für mich keinen Sinn. Warum sollte man nur eine Art von Datei aus einem Verzeichnis im Klassenpfad anstelle des gesamten Verzeichnisses betrachten? Es zwingt Sie, nur eine Eigenschaftendatei zu verwenden, was imo nicht gut ist. Wie in Tomcat kann ich common.loader so konfigurieren, dass ein bestimmtes Verzeichnis (und alles, was darin enthalten ist) in den Klassenpfad eingefügt wird. Warum kann der Bootloader das Boot nicht unterstützen?
Nir
3
Das Zitieren von Dokumentation ist nicht hilfreich. Wenn die Dokumentation klar wäre (genug? Auf die besonders benötigte Weise?), Wäre die Frage nicht notwendig. In diesem Fall ist beispielsweise nicht klar, wie config.locationund wie sie config.namesinteragieren, obwohl es für Personen, die bereits wissen, wie sie interagieren, wahrscheinlich klar zu sein scheint. Können Sie Ihre Antwort aktualisieren, um der Dokumentation etwas hinzuzufügen ?
Narfanator
13
Dies sollte aktualisiert werden, da das Verhalten von spring.config.locationjetzt den Standard überschreibt, anstatt ihn hinzuzufügen. Sie müssen verwenden spring.config.additional-location, um die Standardeinstellungen beizubehalten. Dies ist eine Verhaltensänderung von 1.x auf 2.x.
Robin
32

Beim Spring-Boot funktioniert die Datei spring.config.location. Geben Sie lediglich durch Kommas getrennte Eigenschaftendateien an.

siehe den folgenden Code

@PropertySource(ignoreResourceNotFound=true,value="classpath:jdbc-${spring.profiles.active}.properties")
public class DBConfig{

     @Value("${jdbc.host}")
        private String jdbcHostName;
     }
}

Man kann die Standardversion von jdbc.properties in die Anwendung einfügen. Hier können die externen Versionen eingestellt werden.

java -jar target/myapp.jar --spring.config.location=classpath:file:///C:/Apps/springtest/jdbc.properties,classpath:file:///C:/Apps/springtest/jdbc-dev.properties

Basierend auf dem mit der Eigenschaft spring.profiles.active festgelegten Profilwert wird der Wert von jdbc.host erfasst. Also wann (unter Windows)

set spring.profiles.active=dev

jdbc.host übernimmt den Wert von jdbc-dev.properties.

zum

set spring.profiles.active=default

jdbc.host übernimmt den Wert von jdbc.properties.

Ganesh Jadhav
quelle
Ich glaube nicht, dass der erste Codeblock funktionieren würde. Ich weiß, wie ich mich in diesem Fall niedergeschlagen habe und dieser Antwort gefolgt bin . Siehe jira.springsource.org/browse/SPR-8539, auf die in der Antwort verwiesen wird, für eine anständige Erklärung.
Sowka
27

Spring Boot 1.X und Spring Boot 2.X bieten nicht die gleichen Optionen und Verhaltensweisen für das Externalized Configuration .

Die sehr gute Antwort von M. Deinum bezieht sich auf die Besonderheiten von Spring Boot 1.
Ich werde hier für Spring Boot 2 aktualisieren.

Quellen und Reihenfolge der Umgebungseigenschaften

Spring Boot 2 verwendet eine ganz bestimmte PropertySourceReihenfolge, die ein sinnvolles Überschreiben von Werten ermöglicht. Eigenschaften werden in der folgenden Reihenfolge berücksichtigt:

  • Eigenschaften der globalen Einstellungen von Devtools in Ihrem Home-Verzeichnis (~ / .spring-boot-devtools.properties, wenn devtools aktiv ist).

  • @TestPropertySource Anmerkungen zu Ihren Tests.

  • @SpringBootTest#propertiesAnmerkungsattribut für Ihre Tests. Kommandozeilenargumente.

  • Eigenschaften von SPRING_APPLICATION_JSON(Inline-JSON, eingebettet in eine Umgebungsvariable oder Systemeigenschaft).

  • ServletConfig Init-Parameter.

  • ServletContext Init-Parameter.

  • JNDI-Attribute von java:comp/env.

  • Java-Systemeigenschaften ( System.getProperties()).

  • Betriebssystemumgebungsvariablen.

  • A RandomValuePropertySource, das Eigenschaften nur zufällig hat. *.

  • Profilspezifische Anwendungseigenschaften außerhalb Ihres verpackten Glases ( application-{profile}.propertiesund YAML-Varianten).

  • Profilspezifische Anwendungseigenschaften, die in Ihrem Glas enthalten sind ( application-{profile}.propertiesund YAML-Varianten).

  • Anwendungseigenschaften außerhalb Ihres verpackten Glases ( application.propertiesund YAML-Varianten).

  • Anwendungseigenschaften in Ihrem Glas ( application.propertiesund YAML-Varianten).

  • @PropertySourceAnmerkungen zu Ihren @ConfigurationKlassen. Standardeigenschaften (durch Einstellung festgelegt SpringApplication.setDefaultProperties).

Um externe Eigenschaftendateien anzugeben, sollten Sie folgende Optionen interessieren:

  • Profilspezifische Anwendungseigenschaften außerhalb Ihres verpackten Glases ( application-{profile}.propertiesund YAML-Varianten).

  • Anwendungseigenschaften außerhalb Ihres verpackten Glases ( application.propertiesund YAML-Varianten).

  • @PropertySourceAnmerkungen zu Ihren @ConfigurationKlassen. Standardeigenschaften (durch Einstellung festgelegt SpringApplication.setDefaultProperties).

Sie können nur eine dieser 3 Optionen verwenden oder sie gemäß Ihren Anforderungen kombinieren.
In sehr einfachen Fällen reicht es beispielsweise aus, nur profilspezifische Eigenschaften zu verwenden. In anderen Fällen möchten Sie möglicherweise sowohl profilspezifische Eigenschaften als auch Standardeigenschaften und verwenden@PropertySource .

Standardspeicherorte für application.properties-Dateien

Bei application.propertiesDateien (und Varianten) lädt Spring sie standardmäßig in der folgenden Reihenfolge und fügt ihre Eigenschaften in der Umgebung hinzu:

  • Ein / config-Unterverzeichnis des aktuellen Verzeichnisses

  • Das aktuelle Verzeichnis

  • Ein Klassenpfad / Konfigurationspaket

  • Die Klassenpfadwurzel

Die höheren Prioritäten sind so wörtlich :
classpath:/,classpath:/config/,file:./,file:./config/.

Wie verwende ich Eigenschaftendateien mit bestimmten Namen?

Die Standardspeicherorte reichen nicht immer aus: Die Standardspeicherorte wie der Standarddateiname ( application.properties) passen möglicherweise nicht. Außerdem müssen Sie wie in der OP-Frage möglicherweise mehrere andere Konfigurationsdateien als application.properties(und die Variante) angeben .
Also spring.config.namewird nicht genug sein.

In diesem Fall sollten Sie mithilfe der spring.config.locationUmgebungseigenschaft (eine durch Kommas getrennte Liste von Verzeichnispositionen oder Dateipfaden) einen expliziten Speicherort angeben.
Um frei über das Dateinamenmuster zu sein, bevorzugen Sie die Liste der Dateipfade gegenüber der Liste der Verzeichnisse.
Zum Beispiel so:

java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

Auf diese Weise ist es am ausführlichsten, nur den Ordner anzugeben, aber es ist auch die Möglichkeit, unsere Konfigurationsdateien sehr genau anzugeben und die effektiv verwendeten Eigenschaften klar zu dokumentieren.

spring.config.location ersetzt jetzt Standardspeicherorte, anstatt sie hinzuzufügen

Bei Spring Boot 1 spring.config.locationfügt das Argument bestimmte Speicherorte in der Spring-Umgebung hinzu.
Ab Spring Boot 2 werden jedoch spring.config.locationdie von Spring verwendeten Standardspeicherorte durch die angegebenen Speicherorte in der Spring-Umgebung ersetzt, wie in der Dokumentation angegeben .

Wenn benutzerdefinierte Konfigurationsspeicherorte mithilfe von konfiguriert werden spring.config.location, ersetzen sie die Standardspeicherorte. Wenn beispielsweise spring.config.locationmit dem Wert konfiguriert ist classpath:/custom-config/, file:./custom-config/wird die Suchreihenfolge der folgenden:

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.locationAuf diese Weise können Sie jetzt sicherstellen, dass eine application.propertiesDatei explizit angegeben werden muss.
Für über JARs, die keine application.propertiesDateien verpacken sollen, ist das ziemlich nett.

Um das alte Verhalten bei der spring.config.locationVerwendung von Spring Boot 2 beizubehalten, können Sie die neue spring.config.additional-locationEigenschaft verwenden. Stattdessen werden spring.config.locationweiterhin die in der Dokumentation angegebenen Speicherorte hinzugefügt :

Wenn benutzerdefinierte Konfigurationsspeicherorte mithilfe von konfiguriert werden spring.config.additional-location, werden sie alternativ zusätzlich zu den Standardspeicherorten verwendet.


In der Praxis

Angenommen, Sie haben wie in der OP-Frage 2 externe Eigenschaftendateien anzugeben und 1 Eigenschaftendatei im Uber-JAR.

So verwenden Sie nur die von Ihnen angegebenen Konfigurationsdateien:

-Dspring.config.location=classpath:/job1.properties,classpath:/job2.properties,classpath:/applications.properties   

So fügen Sie diesen an den Standardspeicherorten Konfigurationsdateien hinzu:

-Dspring.config.additional-location=classpath:/job1.properties,classpath:/job2.properties

classpath:/applications.properties ist im letzten Beispiel nicht erforderlich, da die Standardspeicherorte dies haben und die Standardspeicherorte hier nicht überschrieben, sondern erweitert werden.

davidxxx
quelle
Ihre Antwort ist wirklich vollständig, außer in einem Punkt: Wo findet Spring die externe Konfiguration job1.properties auf der Festplatte, wenn Sie nur Folgendes angeben: "classpath: /job1.properties"? Wie haben Sie hier Ihr Verzeichnis mit externen Eigenschaften zum Klassenpfad hinzugefügt?
Tristan
@Tristan Grundsätzlich kann Spring einen application.propertiesmit allen Parametern und mehrere ${file_name}.propertiesmit teilweise definierten Eigenschaftensätzen lesen . Wenn Sie also @PropertySourceoder andere starke Links zu Dateien verwenden, können Sie andere externe Dateien erstellen und diese Eigenschaften überschreiben (z. B. von classpath:file.properties).
Mister_Jesus
23

Werfen Sie einen Blick auf den PropertyPlaceholderConfigurer. Ich finde ihn klarer zu verwenden als Anmerkungen.

z.B

@Configuration
public class PropertiesConfiguration {


    @Bean
    public PropertyPlaceholderConfigurer properties() {
        final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
//        ppc.setIgnoreUnresolvablePlaceholders(true);
        ppc.setIgnoreResourceNotFound(true);

        final List<Resource> resourceLst = new ArrayList<Resource>();

        resourceLst.add(new ClassPathResource("myapp_base.properties"));
        resourceLst.add(new FileSystemResource("/etc/myapp/overriding.propertie"));
        resourceLst.add(new ClassPathResource("myapp_test.properties"));
        resourceLst.add(new ClassPathResource("myapp_developer_overrides.properties")); // for Developer debugging.

        ppc.setLocations(resourceLst.toArray(new Resource[]{}));

        return ppc;
    }
user3206144
quelle
Vielen Dank für diese Antwort. Können Sie mir bitte mitteilen, wie ich dasselbe in einem Projekt erreichen kann, das ähnliche XML-Konfigurationen für verschiedene Dinge ohne XML-Basisdatei aufweist? Ihre Antwort oben hat mir bei anderen Projekten geholfen, die auf Anmerkungen basierten. Nochmals vielen Dank dafür.
Chetan
8

Dies ist ein einfacher Ansatz mit Federstiefel

TestClass.java

@Configuration
@Profile("one")
@PropertySource("file:/{selected location}/app.properties")
public class TestClass {

    @Autowired
    Environment env;

    @Bean
    public boolean test() {
        System.out.println(env.getProperty("test.one"));
        return true;
    }
}

den Kontext app.properties an Ihrem ausgewählten Speicherort

test.one = 1234

Ihre Spring Boot-Anwendung

@SpringBootApplication

public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(testApplication.class, args);
    }
}

und den vordefinierten Kontext application.properties

spring.profiles.active = one

Sie können beliebig viele Konfigurationsklassen schreiben und diese aktivieren / deaktivieren, indem Sie spring.profiles.active festlegen = den Profilnamen / die Profilnamen {durch Kommas getrennt}

Wie Sie sehen können, ist Spring Boot großartig. Es braucht nur einige Zeit, um sich damit vertraut zu machen. Erwähnenswert ist, dass Sie @Value auch auf Ihren Feldern verwenden können

@Value("${test.one}")
String str;
Farzan Skt
quelle
7

Ich hatte das gleiche Problem. Ich wollte die Möglichkeit haben, eine interne Konfigurationsdatei beim Start mit einer externen Datei zu überschreiben, ähnlich der Erkennung von Spring Boot application.properties. In meinem Fall handelt es sich um eine user.properties-Datei, in der die Benutzer meiner Anwendungen gespeichert sind.

Meine Anforderungen:

Laden Sie die Datei von den folgenden Speicherorten (in dieser Reihenfolge)

  1. Der Klassenpfad
  2. Ein / config- Unterverzeichnis des aktuellen Verzeichnisses.
  3. Das aktuelle Verzeichnis
  4. Aus dem Verzeichnis oder einem Dateispeicherort, der beim Start durch einen Befehlszeilenparameter angegeben wird

Ich habe die folgende Lösung gefunden:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.Properties;

import static java.util.Arrays.stream;

@Configuration
public class PropertiesConfig {

    private static final Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);

    private final static String PROPERTIES_FILENAME = "user.properties";

    @Value("${properties.location:}")
    private String propertiesLocation;

    @Bean
    Properties userProperties() throws IOException {
        final Resource[] possiblePropertiesResources = {
                new ClassPathResource(PROPERTIES_FILENAME),
                new PathResource("config/" + PROPERTIES_FILENAME),
                new PathResource(PROPERTIES_FILENAME),
                new PathResource(getCustomPath())
        };
        // Find the last existing properties location to emulate spring boot application.properties discovery
        final Resource propertiesResource = stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .reduce((previous, current) -> current)
                .get();
        final Properties userProperties = new Properties();

        userProperties.load(propertiesResource.getInputStream());

        LOG.info("Using {} as user resource", propertiesResource);

        return userProperties;
    }

    private String getCustomPath() {
        return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + PROPERTIES_FILENAME;
    }

}

Jetzt verwendet die Anwendung die Klassenpfadressource, sucht jedoch auch an den anderen angegebenen Speicherorten nach einer Ressource. Die letzte vorhandene Ressource wird ausgewählt und verwendet. Ich kann meine App mit java -jar myapp.jar --properties.location = / directory / myproperties.properties starten, um einen Eigenschaftenspeicherort zu verwenden, der mein Boot schwimmt.

Ein wichtiges Detail hier: Verwenden Sie eine leere Zeichenfolge als Standardwert für die Eigenschaft properties.location in der Annotation @Value, um Fehler zu vermeiden, wenn die Eigenschaft nicht festgelegt ist.

Die Konvention für einen properties.location lautet: Verwenden Sie ein Verzeichnis oder einen Pfad zu einer Eigenschaftendatei als properties.location.

Wenn Sie nur bestimmte Eigenschaften überschreiben möchten, kann eine PropertiesFactoryBean mit setIgnoreResourceNotFound (true) verwendet werden, wobei das Ressourcenarray als Speicherorte festgelegt ist.

Ich bin sicher, dass diese Lösung erweitert werden kann, um mehrere Dateien zu verarbeiten ...

BEARBEITEN

Hier meine Lösung für mehrere Dateien :) Wie zuvor kann dies mit einer PropertiesFactoryBean kombiniert werden.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;

import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;

@Configuration
class PropertiesConfig {

    private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
    private final static String[] PROPERTIES_FILENAMES = {"job1.properties", "job2.properties", "job3.properties"};

    @Value("${properties.location:}")
    private String propertiesLocation;

    @Bean
    Map<String, Properties> myProperties() {
        return stream(PROPERTIES_FILENAMES)
                .collect(toMap(filename -> filename, this::loadProperties));
    }

    private Properties loadProperties(final String filename) {
        final Resource[] possiblePropertiesResources = {
                new ClassPathResource(filename),
                new PathResource("config/" + filename),
                new PathResource(filename),
                new PathResource(getCustomPath(filename))
        };
        final Resource resource = stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .reduce((previous, current) -> current)
                .get();
        final Properties properties = new Properties();

        try {
            properties.load(resource.getInputStream());
        } catch(final IOException exception) {
            throw new RuntimeException(exception);
        }

        LOG.info("Using {} as user resource", resource);

        return properties;
    }

    private String getCustomPath(final String filename) {
        return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + filename;
    }

}
mxsb
quelle
schöne Problemumgehung. So konstruiert Java8! Jedenfalls kann ich das nicht verwenden, da ich mehrere Properties Beans brauche, nicht nur eine. Wenn Sie meine EDITS sehen, ist meine Problemumgehung für meinen Anwendungsfall ziemlich ähnlich und ordentlich.
Nir
Ich habe eine Version für mehrere Dateien veröffentlicht, nur der Vollständigkeit
halber
6

Mit Spring Boot können wir verschiedene Profile schreiben, um für verschiedene Umgebungen zu schreiben. Beispielsweise können wir separate Eigenschaftendateien für Produktions-, QA- und lokale Umgebungen haben

Die Datei application-local.properties mit Konfigurationen gemäß meinem lokalen Computer ist

spring.profiles.active=local

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=users
spring.data.mongodb.username=humble_freak
spring.data.mongodb.password=freakone

spring.rabbitmq.host=localhost
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.port=5672

rabbitmq.publish=true

Ebenso können wir application-prod.properties und application-qa.properties so viele Eigenschaftendateien schreiben, wie wir möchten

Schreiben Sie dann einige Skripte, um die Anwendung für verschiedene Umgebungen zu starten, z

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod
Demütiger Freak
quelle
5

Ich hatte gerade ein ähnliches Problem und habe schließlich die Ursache herausgefunden: Die Datei application.properties hatte die falschen Besitz- und rwx-Attribute. Als Tomcat gestartet wurde, befand sich die Datei application.properties am richtigen Speicherort, gehörte jedoch einem anderen Benutzer:

$ chmod 766 application.properties

$ chown tomcat application.properties
Robjwilkins
quelle
Ich glaube ich habe ein ähnliches Problem. Ich habe Tomcat im opt-Ordner installiert. Wo haben Sie Ihre Bewerbungsunterlagen abgelegt? Soll ich auch die Ordnerattribute ändern?
anakin59490
3

Eine modifizierte Version der @ mxsb-Lösung, mit der wir mehrere Dateien definieren können. In meinem Fall handelt es sich um XML-Dateien.

In meiner application-dev.yml habe ich diese Konfiguration hinzugefügt, mit der ich alle yml-Dateien mit -dev.yml einfügen kann. Dies kann auch eine Liste bestimmter Dateien sein. "Klassenpfad: /test/test.yml, Klassenpfad: /test2/test.yml"

application:
  properties:
    locations: "classpath*:/**/*-dev.yml"

Dies hilft, eine Eigenschaftskarte zu erhalten.

@Configuration

public class PropertiesConfig {

private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);

@Value("${application.properties.locations}")
private String[] locations;

@Autowired
private ResourceLoader rl;

@Bean
Map<String, Properties> myProperties() {
    return stream(locations)
            .collect(toMap(filename -> filename, this::loadProperties));
}

private Properties loadProperties(final String filename) {

    YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
    try {
        final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
        final Properties properties = new Properties();
        stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .map(resource1 -> {
                    try {
                        return loader.load(resource1.getFilename(), resource1);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }).flatMap(l -> l.stream())
                .forEach(propertySource -> {
                    Map source = ((MapPropertySource) propertySource).getSource();
                    properties.putAll(source);
                });

        return properties;
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
}

Wenn ich jedoch wie in meinem Fall wollte, musste ich yml-Dateien für jedes Profil teilen und laden und diese vor der Initialisierung der Beans direkt in die Spring-Konfiguration einfügen.

config
    - application.yml
    - application-dev.yml
    - application-prod.yml
management
    - management-dev.yml
    - management-prod.yml

... Du hast die Idee

Die Komponente ist etwas anders

@Component
public class PropertiesConfigurer extends     PropertySourcesPlaceholderConfigurer
    implements EnvironmentAware, InitializingBean {

private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfigurer.class);

private String[] locations;

@Autowired
private ResourceLoader rl;
private Environment environment;

@Override
public void setEnvironment(Environment environment) {
    // save off Environment for later use
    this.environment = environment;
    super.setEnvironment(environment);
}

@Override
public void afterPropertiesSet() throws Exception {
    // Copy property sources to Environment
    MutablePropertySources envPropSources = ((ConfigurableEnvironment) environment).getPropertySources();
    envPropSources.forEach(propertySource -> {
        if (propertySource.containsProperty("application.properties.locations")) {
            locations = ((String) propertySource.getProperty("application.properties.locations")).split(",");
            stream(locations).forEach(filename -> loadProperties(filename).forEach(source ->{
                envPropSources.addFirst(source);
            }));
        }
    });
}


private List<PropertySource> loadProperties(final String filename) {
    YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
    try {
        final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
        final Properties properties = new Properties();
        return stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .map(resource1 -> {
                    try {
                        return loader.load(resource1.getFilename(), resource1);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }).flatMap(l -> l.stream())
                .collect(Collectors.toList());
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

}}

Codewarrior
quelle
3

Wenn Sie die in Ihrer Datei application.properties angegebenen Werte überschreiben möchten, können Sie Ihr aktives Profil ändern, während Sie Ihre Anwendung ausführen, und eine Anwendungseigenschaftendatei für das Profil erstellen. Geben Sie beispielsweise das aktive Profil "override" an. Anschließend können Sie unter der Annahme, dass Sie Ihre neue Anwendungseigenschaftendatei mit dem Namen "application-override.properties" unter / tmp erstellt haben, ausführen

java -jar yourApp.jar --spring.profiles.active="override" --spring.config.location="file:/tmp/,classpath:/" 

Die unter spring.config.location angegebenen Werte werden in umgekehrter Reihenfolge ausgewertet. In meinem Beispiel wird also zuerst der Klassenpatient und dann der Dateiewert ausgewertet.

Wenn sich die JAR-Datei und die Datei "application-override.properties" im aktuellen Verzeichnis befinden, können Sie sie einfach verwenden

java -jar yourApp.jar --spring.profiles.active="override"

da Spring Boot die Eigenschaftendatei für Sie findet

acaruci
quelle
1
Spring wird angewiesen, das "Override" -Profil als aktives Profil zu verwenden. es würde in der Tat den in der Datei application.yml oder application.properties angegebenen Wert
überschreiten
Es wird im Ordner nach Konfigurationsdateien .ymal oder .properties gesucht. In meinem Fall habe ich nur application-profile.yml eingefügt, dann dauert es richtig. Danke @acaruci, es war eine schöne Reise
Ahmed Salem
0

Ich habe festgestellt, dass dies ein nützliches Muster ist:

@RunWith(SpringRunner)
@SpringBootTest(classes = [ TestConfiguration, MyApplication ],
        properties = [
                "spring.config.name=application-MyTest_LowerImportance,application-MyTest_MostImportant"
                ,"debug=true", "trace=true"
        ]
)

Hier überschreiben wir die Verwendung von "application.yml", um "application-MyTest_LowerImportance.yml" und auch "application-MyTest_MostImportant.yml" zu verwenden
(Spring sucht auch nach .properties-Dateien).

Als zusätzlichen Bonus sind auch die Debug- und Trace-Einstellungen in einer separaten Zeile enthalten, damit Sie sie bei Bedarf auskommentieren können.]

Das Debuggen / Trace ist unglaublich nützlich, da Spring die Namen aller geladenen und der zu ladenden Dateien speichert.
Zur Laufzeit werden in der Konsole folgende Zeilen angezeigt:

TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.properties' (file:./config/application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.xml' (file:./config/application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.yml' (file:./config/application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.yaml' (file:./config/application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.properties' (file:./config/application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.xml' (file:./config/application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.yml' (file:./config/application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.yaml' (file:./config/application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.properties' (file:./application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.xml' (file:./application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.yml' (file:./application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.yaml' (file:./application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.properties' (file:./application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.xml' (file:./application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.yml' (file:./application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.yaml' (file:./application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.xml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.xml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.xml' resource not found
DEBUG 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_MostImportant.yml' (classpath:/application-MyTest_MostImportant.yml)
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.xml' resource not found
DEBUG 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_LowerImportance.yml' (classpath:/application-MyTest_LowerImportance.yml)
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant-test.properties' (file:./config/application-MyTest_MostImportant-test.properties) resource not found
davidfrancis
quelle
-1

Ich bin auf viele Probleme gestoßen, als ich versucht habe, dies herauszufinden. Hier ist mein Setup,

Dev Env: Windows 10, Java: 1.8.0_25, Spring Boot: 2.0.3.RELEASE, Spring: 5.0.7.RELEASE

Was ich gefunden habe, ist, dass der Frühling am Konzept "Sinnvolle Standardeinstellungen für die Konfiguration" festhält. Dies bedeutet, dass Sie alle Ihre Eigenschaftendateien als Teil Ihrer Kriegsdatei haben müssen. Dort können Sie sie mit der Befehlszeileneigenschaft "--spring.config.additional-location" überschreiben, um auf externe Eigenschaftendateien zu verweisen. Dies funktioniert jedoch NICHT, wenn die Eigenschaftendateien nicht Teil der ursprünglichen Kriegsdatei sind.

Demo-Code: https://github.com/gselvara/spring-boot-property-demo/tree/master

gselvara
quelle