Spring Boot e più file di configurazione esterni


125

Ho più file di proprietà che voglio caricare da classpath. C'è un set predefinito in /src/main/resourcescui fa parte di myapp.jar. Mi springcontextaspetto che i file si trovino sul classpath. vale a dire

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

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

Ho anche bisogno dell'opzione per sovrascrivere queste proprietà con un set esterno. Ho una cartella di configurazione esterna in cwd. Come da primavera, la cartella di configurazione del documento di avvio dovrebbe essere su classpath. Ma non è chiaro da doc se sovrascriverà solo applicaiton.propertiesda lì o tutte le proprietà in config.

Quando l'ho testato, application.propertiesviene prelevato solo e il resto delle proprietà viene ancora ritirato /src/main/resources. Ho provato a fornirli come elenco separato da virgole a, spring.config.locationma il set predefinito non viene ancora sovrascritto.

Come faccio a fare in modo che più file di configurazione esterni sovrascrivano quelli predefiniti?

Come soluzione alternativa ho attualmente utilizzato app.config.location(proprietà specifica dell'app) che fornisco tramite la riga di comando. vale a dire

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

e ho cambiato il mio applicationcontextin

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

Ed è così che creo la separazione tra file e classpath durante il caricamento dell'applicazione.
Modifiche:

//psuedo code

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

Mi piacerebbe davvero non utilizzare la soluzione alternativa di cui sopra e fare in modo che la molla sovrascriva tutti i file di configurazione esterni sul classpath come fa per il application.propertiesfile.


4
Il application.propertiessarà sempre essere caricato, con spring.config.locationè possibile aggiungere ulteriori posizioni di configurazione che vengono controllati per i file (cioè quando si termina con una /) se si mette una virgola separati in là che punta al file di coloro che verranno caricati. Questo è anche spiegato nella Spring Boot Reference Guide qui
M. Deinum

Risposte:


156

Quando si utilizza Spring Boot, le proprietà vengono caricate nell'ordine seguente (vedere Configurazione esterna nella guida di riferimento di Spring Boot).

  1. Argomenti della riga di comando.
  2. Proprietà del sistema Java (System.getProperties ()).
  3. Variabili di ambiente del sistema operativo.
  4. Attributi JNDI da java: comp / env
  5. Un RandomValuePropertySource che ha solo proprietà in random. *.
  6. Proprietà dell'applicazione al di fuori del vaso confezionato (application.properties incluse YAML e varianti del profilo).
  7. Proprietà dell'applicazione confezionate all'interno del tuo jar (application.properties incluse YAML e le varianti del profilo).
  8. Annotazioni @PropertySource sulle classi @Configuration.
  9. Proprietà predefinite (specificate utilizzando SpringApplication.setDefaultProperties).

Quando si risolvono proprietà (ovvero la @Value("${myprop}")risoluzione viene eseguita in ordine inverso (quindi a partire da 9).

Per aggiungere file diversi è possibile utilizzare le spring.config.locationproprietà che accettano un elenco separato da virgole di file di proprietà o percorso di file (directory).

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

Quello sopra aggiungerà una directory che verrà consultata per i application.propertiesfile.

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

Questo aggiungerà il 2 file delle proprietà ai file che vengono caricati.

I file e le posizioni di configurazione predefiniti vengono caricati prima di spring.config.locationquelli specificati in aggiunta , il che significa che questi ultimi sovrascriveranno sempre le proprietà impostate in quelli precedenti. (Vedi anche questa sezione della Spring Boot Reference Guide).

Se spring.config.location contiene directory (al contrario dei file) dovrebbero terminare con / (e verranno aggiunti con i nomi generati spring.config.nameprima di essere caricati). classpath:,classpath:/config,file:,file:config/Viene sempre utilizzato il percorso di ricerca predefinito , indipendentemente dal valore di spring.config.location. In questo modo puoi impostare i valori predefiniti per la tua applicazione in application.properties(o qualsiasi altro nome base con cui scegli spring.config.name) e sovrascriverlo in fase di esecuzione con un file diverso, mantenendo i valori predefiniti.

AGGIORNAMENTO: poiché il comportamento di spring.config.location ora sovrascrive il valore predefinito invece di aggiungerlo. È necessario utilizzare spring.config.additional-location per mantenere i valori predefiniti. Si tratta di una modifica del comportamento da 1.x a 2.x


2
Grazie ma ho già letto questo documento di riferimento e il seguito mi confonde "-Dspring.config.location = tuo / config / dir / Quello sopra aggiungerà una directory che verrà consultata per i file application.properties." Cosa significa per file application.properties. Questo è solo un file. In ogni caso, se è in grado di raccogliere l'intera directory con "/" alla fine, non è necessario specificarli come elenchi separati da virgole. Penso di aver provato entrambi gli approcci come ho detto nel mio post, ma ci proverò ancora
nir

Come indicato nel documento, verrà selezionato verrà consultato come le altre posizioni predefinite per application.propertiese application-[env].properties. Non tiene conto di altri file di proprietà. Questo è anche indicato nella guida di riferimento (nella sezione il collegamento conduce e la citazione dalla guida di riferimento).
M. Deinum

1
Sì, ma questo è ciò che non ha senso per me .. perché considerare solo un tipo di file da una directory su classpath invece dell'intera directory. Ti costringe a usare solo un file di proprietà che non è buono. Come in Tomcat, posso configurare common.loader per mettere una directory particolare (e tutto ciò che è al suo interno) su classpath perché non è possibile avviare il classloader può supportarlo.
NIR

3
La documentazione di citazione non è utile. Se la documentazione fosse chiara (abbastanza? Nel modo particolarmente necessario?) Allora la domanda non sarebbe necessaria. Per esempio, in questo caso, in realtà non è chiaro come config.locatione config.namesinteragiscono, anche se probabilmente sembra chiaro a persone che già conoscono il modo in cui interagiscono. Puoi aggiornare la tua risposta per aggiungere qualcosa alla documentazione?
Narfanator

13
Questo dovrebbe essere aggiornato, poiché il comportamento di spring.config.locationora sovrascrive il valore predefinito invece di aggiungerlo. È necessario utilizzare spring.config.additional-locationper mantenere le impostazioni predefinite. Si tratta di una modifica del comportamento da 1.x a 2.x.
Robin

32

Con Spring boot, spring.config.location funziona, basta fornire file delle proprietà separati da virgole.

vedere il codice sottostante

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

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

si può mettere la versione predefinita di jdbc.properties all'interno dell'applicazione. Le versioni esterne possono essere impostate su questo.

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

In base al valore del profilo impostato utilizzando la proprietà spring.profiles.active, verrà prelevato il valore di jdbc.host. Quindi quando (su Windows)

set spring.profiles.active=dev

jdbc.host prenderà il valore da jdbc-dev.properties.

per

set spring.profiles.active=default

jdbc.host prenderà il valore da jdbc.properties.


Non credo che il primo dei blocchi di codice funzionerebbe. Lo so come mi sono bloccato su questo e ho seguito questa risposta . Vedi jira.springsource.org/browse/SPR-8539 a cui si fa riferimento nella risposta per una spiegazione decente.
Sowka

27

Spring Boot 1.X e Spring Boot 2.X non forniscono le stesse opzioni e comportamenti per il Externalized Configuration .

L'ottima risposta di M. Deinum si riferisce alle specificità di Spring Boot 1.
Aggiornerò per Spring Boot 2 qui.

Fonti e ordine delle proprietà dell'ambiente

Spring Boot 2 utilizza un PropertySourceordine molto particolare progettato per consentire una sostituzione ragionevole dei valori. Le proprietà sono considerate nel seguente ordine:

  • Proprietà delle impostazioni globali di Devtools nella directory home (~ / .spring-boot-devtools.properties quando devtools è attivo).

  • @TestPropertySource annotazioni sui tuoi test.

  • @SpringBootTest#propertiesattributo annotation sui tuoi test. Argomenti della riga di comando.

  • Proprietà da SPRING_APPLICATION_JSON(JSON in linea incorporato in una variabile di ambiente o in una proprietà di sistema).

  • ServletConfig parametri di inizializzazione.

  • ServletContext parametri di inizializzazione.

  • Attributi JNDI da java:comp/env.

  • Proprietà del sistema Java ( System.getProperties()).

  • Variabili di ambiente del sistema operativo.

  • A RandomValuePropertySourceche ha proprietà solo in modo casuale. *.

  • Proprietà dell'applicazione specifiche del profilo al di fuori del vaso confezionato ( application-{profile}.propertiese delle varianti YAML).

  • Proprietà dell'applicazione specifiche del profilo contenute nel tuo jar ( application-{profile}.propertiese varianti YAML).

  • Proprietà dell'applicazione all'esterno del vaso confezionato ( application.propertiese varianti YAML).

  • Proprietà dell'applicazione confezionate all'interno del tuo jar ( application.propertiese varianti YAML).

  • @PropertySourceannotazioni sulle tue @Configurationclassi. Proprietà predefinite (specificate dall'impostazione SpringApplication.setDefaultProperties).

Per specificare i file delle proprietà esterne, queste opzioni dovrebbero interessarti:

  • Proprietà dell'applicazione specifiche del profilo al di fuori del vaso confezionato ( application-{profile}.propertiese delle varianti YAML).

  • Proprietà dell'applicazione all'esterno del vaso confezionato ( application.propertiese varianti YAML).

  • @PropertySourceannotazioni sulle tue @Configurationclassi. Proprietà predefinite (specificate dall'impostazione SpringApplication.setDefaultProperties).

È possibile utilizzare solo una di queste 3 opzioni o combinarle in base alle proprie esigenze.
Ad esempio, per casi molto semplici è sufficiente utilizzare solo proprietà specifiche del profilo, ma in altri casi è possibile utilizzare sia le proprietà specifiche del profilo, sia le proprietà predefinite e @PropertySource.

Percorsi predefiniti per i file application.properties

Per quanto riguarda i application.propertiesfile (e le varianti), per impostazione predefinita Spring li carica e aggiunge le loro proprietà nell'ambiente da questi nel seguente ordine:

  • Una sottodirectory / config della directory corrente

  • La directory corrente

  • Un pacchetto classpath / config

  • La radice del percorso di classe

Le priorità più elevati sono così alla lettera:
classpath:/,classpath:/config/,file:./,file:./config/.

Come utilizzare i file delle proprietà con nomi specifici?

Le posizioni predefinite non sono sempre sufficienti: le posizioni predefinite come il nome file predefinito ( application.properties) potrebbero non essere adatte. Inoltre, come nella domanda OP potrebbe essere necessario specificare più file di configurazione diversi da application.properties(e variant).
Quindi spring.config.namenon sarà abbastanza.

In questo caso è necessario fornire una posizione esplicita utilizzando la spring.config.locationproprietà environment (che è un elenco separato da virgole di posizioni di directory o percorsi di file).
Per essere libero sul pattern dei nomi dei file, prediligi l'elenco dei percorsi dei file rispetto all'elenco delle directory.
Ad esempio fai così:

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

In questo modo è il più dettagliato quello che specifica solo la cartella ma è anche il modo per specificare molto finemente i nostri file di configurazione e per documentare chiaramente le proprietà effettivamente utilizzate.

spring.config.location ora sostituisce le posizioni predefinite invece di aggiungerle

Con Spring Boot 1, l' spring.config.locationargomento aggiunge posizioni specificate nell'ambiente Spring.
Ma da Spring Boot 2, spring.config.locationsostituisce le posizioni predefinite utilizzate da Spring con le posizioni specificate nell'ambiente Spring come indicato nella documentazione .

Quando le posizioni di configurazione personalizzate vengono configurate utilizzando spring.config.location, sostituiscono le posizioni predefinite. Per esempio, se spring.config.locationè configurato con il valore classpath:/custom-config/, file:./custom-config/l'ordine di ricerca diventa la seguente:

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.locationè ora un modo per assicurarsi che qualsiasi application.propertiesfile debba essere specificato esplicitamente.
Per i JAR uber che non dovrebbero impacchettare application.propertiesfile, è piuttosto carino.

Per mantenere il vecchio comportamento spring.config.locationdurante l'utilizzo di Spring Boot 2 è possibile utilizzare la nuova spring.config.additional-locationproprietà invece di spring.config.locationaggiungere ancora le posizioni come indicato dalla documentazione :

In alternativa, quando le posizioni di configurazione personalizzate vengono configurate utilizzando spring.config.additional-location, vengono utilizzate in aggiunta alle posizioni predefinite.


In pratica

Supponiamo quindi che, come nella domanda OP, tu abbia 2 file delle proprietà esterne da specificare e 1 file delle proprietà incluso nel vaso uber.

Per utilizzare solo i file di configurazione specificati:

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

Per aggiungere file di configurazione a questi nelle posizioni predefinite:

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

classpath:/applications.properties nell'ultimo esempio non è richiesto poiché le posizioni predefinite hanno quello e quelle posizioni predefinite qui non vengono sovrascritte ma estese.


La tua risposta è davvero completa tranne che su una cosa: dove Spring troverà la configurazione esterna job1.properties su disco se specifichi semplicemente: "classpath: /job1.properties"? Come hai aggiunto la tua directory contenente proprietà esterne al classpath qui?
Tristan

@Tristan, fondamentalmente, la molla può leggere uno application.propertiescon tutti i parametri e più ${file_name}.propertiescon insiemi di proprietà definiti parziali. Quindi, se usi @PropertySourceo altri collegamenti forti ai file, puoi creare altri file esterni e sovrascrivere tali proprietà (ad esempio: da classpath:file.properties).
Mister_Jesus

23

Dai un'occhiata al PropertyPlaceholderConfigurer, trovo che sia più chiaro da usare rispetto all'annotazione.

per esempio

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

Grazie mille per questa risposta. Potete farmi sapere come posso ottenere lo stesso risultato in un progetto che ha configurazioni XML simili per cose diverse senza un file XML di base? La tua risposta sopra mi ha aiutato in un altro progetto basato su annotazioni. Grazie ancora per questo.
Chetan

8

questo è un semplice approccio usando lo stivale a molla

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

il contesto app.properties , nella posizione selezionata

test.one = 1234

la tua applicazione di avvio primaverile

@SpringBootApplication

public class TestApplication {

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

e il contesto predefinito application.properties

spring.profiles.active = one

puoi scrivere tutte le classi di configurazione che desideri e abilitarle / disabilitarle semplicemente impostando spring.profiles.active = il nome / i nomi del profilo {separati da virgole}

come puoi vedere lo stivale primaverile è fantastico, ha solo bisogno di un po 'di tempo per familiarizzare, vale la pena ricordare che puoi usare @Value anche sui tuoi campi

@Value("${test.one}")
String str;

7

Ho avuto lo stesso problema. Volevo avere la possibilità di sovrascrivere un file di configurazione interno all'avvio con un file esterno, simile al rilevamento di Spring Boot application.properties. Nel mio caso è un file user.properties in cui sono archiviati gli utenti delle mie applicazioni.

Le mie esigenze:

Carica il file dalle seguenti posizioni (in questo ordine)

  1. Il classpath
  2. Una sottodirectory / config della directory corrente.
  3. La directory corrente
  4. Dalla directory o da un percorso di file fornito da un parametro della riga di comando all'avvio

Ho trovato la seguente soluzione:

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

}

Ora l'applicazione utilizza la risorsa del percorso di classe, ma controlla anche una risorsa nelle altre posizioni date. L'ultima risorsa esistente verrà selezionata e utilizzata. Sono in grado di avviare la mia app con java -jar myapp.jar --properties.location = / directory / myproperties.properties per utilizzare una posizione delle proprietà che fa galleggiare la mia barca.

Un dettaglio importante qui: usa una stringa vuota come valore predefinito per properties.location nell'annotazione @Value per evitare errori quando la proprietà non è impostata.

La convenzione per un properties.location è: utilizzare una directory o un percorso a un file delle proprietà come properties.location.

Se si desidera sovrascrivere solo proprietà specifiche, è possibile utilizzare PropertiesFactoryBean con setIgnoreResourceNotFound (true) con la matrice di risorse impostata come posizioni.

Sono sicuro che questa soluzione può essere estesa per gestire più file ...

MODIFICARE

Ecco la mia soluzione per più file :) Come prima, questo può essere combinato con un PropertiesFactoryBean.

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

}

bella soluzione alternativa. Come quei costrutti java8! in ogni caso non posso usarlo in quanto ho bisogno di più bean di proprietà non solo uno. Se vedi le mie MODIFICHE, la mia soluzione alternativa è abbastanza simile e pulita per il mio caso d'uso.
nir

Ho pubblicato una versione per più file, solo per completezza;)
mxsb

6

lo spring boot ci consente di scrivere diversi profili da scrivere per diversi ambienti, ad esempio possiamo avere file delle proprietà separati per la produzione, qa e ambienti locali

Il file application-local.properties con le configurazioni in base alla mia macchina locale è

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

Allo stesso modo, possiamo scrivere application-prod.properties e application-qa.properties tutti i file delle proprietà che vogliamo

quindi scrivere alcuni script per avviare l'applicazione per diversi ambienti, ad es

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod

5

Ho appena avuto un problema simile a questo e finalmente ho capito la causa: il file application.properties aveva la proprietà e gli attributi rwx sbagliati. Quindi, quando Tomcat ha avviato il file application.properties era nella posizione corretta, ma di proprietà di un altro utente:

$ chmod 766 application.properties

$ chown tomcat application.properties

Penso di avere un problema simile. Ho installato Tomcat nella cartella opt. Dove hai posizionato il file della tua domanda? Devo cambiare anche gli attributi della cartella?
anakin59490

3

Una versione modificata della soluzione @mxsb che ci permette di definire più file e nel mio caso si tratta di file yml.

Nella mia application-dev.yml, ho aggiunto questa configurazione che mi permette di iniettare tutti gli yml che contengono -dev.yml. Può anche essere un elenco di file specifici. "Classpath: /test/test.yml,classpath: /test2/test.yml"

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

Questo aiuta a ottenere una mappa delle proprietà.

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

Tuttavia, se come nel mio caso, volevo dividere i file yml per ogni profilo e caricarli e iniettarli direttamente nella configurazione di primavera prima dell'inizializzazione dei bean.

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

... hai capito

Il componente è leggermente diverso

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

}


3

Se si desidera sovrascrivere i valori specificati nel file application.properties, è possibile modificare il profilo attivo mentre si esegue l'applicazione e creare un file delle proprietà dell'applicazione per il profilo. Quindi, ad esempio, specifichiamo il profilo attivo "override" e quindi, supponendo che tu abbia creato il tuo nuovo file delle proprietà dell'applicazione chiamato "application-override.properties" in / tmp, puoi eseguire

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

I valori specificati in spring.config.location vengono valutati in ordine inverso. Quindi, nel mio esempio, viene valutato prima classpat, quindi il valore del file.

Se il file jar e il file "application-override.properties" si trovano nella directory corrente puoi effettivamente usare semplicemente

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

poiché Spring Boot troverà il file delle proprietà per te


1
Dirà a spring di usare il profilo "override" come tuo profilo attivo;
supererebbe

cercherà all'interno della cartella qualsiasi file di configurazione .ymal o .properties nel mio caso ho messo solo application-profile.yml quindi prende correttamente, Grazie @acaruci è stato un bel viaggio
Ahmed Salem

0

Ho trovato che questo è uno schema utile da seguire:

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

Qui sovrascriviamo l'uso di "application.yml" per utilizzare "application-MyTest_LowerImportance.yml" e anche "application-MyTest_MostImportant.yml"
(Spring cercherà anche i file .properties)

Sono incluse anche come bonus extra le impostazioni di debug e traccia, su una riga separata in modo da poterle commentare se necessario;]

Il debug / trace sono incredibilmente utili in quanto Spring scaricherà i nomi di tutti i file che carica e di quelli che tenta di caricare.
Vedrai righe come questa nella console in fase di esecuzione:

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

-1

Ho riscontrato molti problemi durante il tentativo di capirlo. Ecco la mia configurazione,

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

Quello che ho scoperto è che la primavera si attacca al concetto "Impostazioni predefinite ragionevoli per la configurazione". Ciò in cui questo si traduce è che devi avere tutti i tuoi file di proprietà come parte del tuo file war. Una volta lì, è possibile sovrascriverli utilizzando la proprietà della riga di comando "--spring.config.additional-location" per puntare ai file delle proprietà esterne. Ma questo NON FUNZIONERÀ se i file delle proprietà non fanno parte del file war originale.

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

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.