Spring Boot et plusieurs fichiers de configuration externes

125

J'ai plusieurs fichiers de propriétés que je souhaite charger à partir du chemin de classe. Il existe un ensemble par défaut sous /src/main/resourceslequel fait partie de myapp.jar. Mon springcontexts'attend à ce que les fichiers soient sur le chemin des classes. c'est à dire

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

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

J'ai également besoin de l'option pour remplacer ces propriétés avec un ensemble externe. J'ai un dossier de configuration externe dans cwd. Selon le dossier de configuration de la documentation de démarrage de printemps, il doit se trouver sur le chemin de classe. Mais ce n'est pas clair de la doc s'il ne remplacera que le à applicaiton.propertiespartir de là ou toutes les propriétés de config.

Lorsque je l'ai testé, il n'est application.propertiesrécupéré que et le reste des propriétés est toujours récupéré /src/main/resources. J'ai essayé de les fournir sous forme de liste séparée par des virgules, spring.config.locationmais le jeu par défaut n'est toujours pas remplacé.

Comment faire pour que plusieurs fichiers de configuration externes remplacent ceux par défaut?

Comme solution de contournement, j'utilise actuellement app.config.location(propriété spécifique à l'application) que je fournis via la ligne de commande. c'est à dire

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

et j'ai changé mon applicationcontexten

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

Et c'est ainsi que je fais la séparation entre le fichier et le chemin de classe lors du chargement de l'application.
MODIFIER:

//psuedo code

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

Je voudrais vraiment ne pas utiliser la solution de contournement ci-dessus et que le ressort remplace tous les fichiers de configuration externes sur le chemin de classe comme il le fait pour le application.propertiesfichier.

nir
la source
4
Le application.propertiessera toujours chargé, avec spring.config.locationvous pouvez ajouter des emplacements de configuration supplémentaires qui sont vérifiés pour les fichiers (c'est-à-dire quand il se termine par a /) mais si vous y mettez une liste séparée par des virgules qui pointe vers les fichiers, ceux-ci seront chargés. Ceci est également expliqué dans le Guide de référence de Spring Boot ici
M. Deinum

Réponses:

156

Lors de l'utilisation de Spring Boot, les propriétés sont chargées dans l'ordre suivant (voir Configuration externalisée dans le guide de référence Spring Boot).

  1. Arguments de ligne de commande.
  2. Propriétés du système Java (System.getProperties ()).
  3. Variables d'environnement du système d'exploitation.
  4. Attributs JNDI de java: comp / env
  5. RandomValuePropertySource qui n'a que des propriétés aléatoires. *.
  6. Propriétés de l'application en dehors de votre fichier jar packagé (application.properties, y compris YAML et les variantes de profil).
  7. Propriétés d'application empaquetées dans votre jar (application.properties, y compris YAML et les variantes de profil).
  8. Annotations @PropertySource sur vos classes @Configuration.
  9. Propriétés par défaut (spécifiées à l'aide de SpringApplication.setDefaultProperties).

Lors de la résolution des propriétés (c'est-à-dire que la @Value("${myprop}")résolution se fait dans l'ordre inverse (donc en commençant par 9).

Pour ajouter différents fichiers, vous pouvez utiliser les spring.config.locationpropriétés qui prennent une liste de fichiers de propriétés séparés par des virgules ou l'emplacement des fichiers (répertoires).

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

Celui ci-dessus ajoutera un répertoire qui sera consulté pour les application.propertiesfichiers.

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

Cela ajoutera les 2 fichiers de propriétés aux fichiers chargés.

Les fichiers de configuration et les emplacements par défaut sont chargés avant spring.config.locationceux spécifiés de manière supplémentaire , ce qui signifie que ces derniers remplaceront toujours les propriétés définies dans les précédents. (Voir également cette section du Guide de référence de Spring Boot).

Si spring.config.locationcontient des répertoires (par opposition aux fichiers), ils doivent se terminer par / (et seront ajoutés avec les noms générés spring.config.nameavant d'être chargés). Le chemin de recherche par défaut classpath:,classpath:/config,file:,file:config/est toujours utilisé, quelle que soit la valeur de spring.config.location. De cette façon, vous pouvez définir des valeurs par défaut pour votre application dans application.properties(ou tout autre nom de base avec lequel vous choisissez spring.config.name) et le remplacer lors de l'exécution par un fichier différent, en conservant les valeurs par défaut.

MISE À JOUR: Comme le comportement de spring.config.location remplace désormais la valeur par défaut au lieu d'y ajouter. Vous devez utiliser spring.config.additional-location pour conserver les valeurs par défaut. Il s'agit d'un changement de comportement de 1.x à 2.x

M. Deinum
la source
2
Merci mais j'ai déjà lu ce document de référence et la suite me déroute "-Dspring.config.location = votre / config / dir / Celui ci-dessus ajoutera un répertoire qui sera consulté pour les fichiers application.properties." Qu'est-ce que cela signifie par fichiers application.properties. Ce n'est qu'un fichier. Dans tous les cas, s'il est capable de récupérer le répertoire entier avec "/" à la fin, je n'ai pas besoin de spécifier chacun comme une liste séparée par des virgules. Je pense que j'ai essayé les deux approches comme je l'ai mentionné dans mon article, mais je vais essayer de nouveau
nir
Comme indiqué dans le document, il sera consulté comme les autres emplacements par défaut pour le application.propertieset application-[env].properties. Il ne prend pas en compte les autres fichiers de propriétés. Ceci est également indiqué dans le guide de référence (dans la section le lien mène vers et le devis du guide de référence).
M. Deinum
1
Oui mais c'est ce qui n'a pas de sens pour moi .. pourquoi ne considérer qu'un seul type de fichier à partir d'un répertoire sur classpath au lieu du répertoire entier. Cela vous oblige à n'utiliser qu'un seul fichier de propriétés, ce qui n'est pas bon pour moi. Comme dans tomcat, je peux configurer common.loader pour mettre un répertoire particulier (et tout ce qu'il contient) sur le chemin de classe, pourquoi le chargeur de classe ne peut pas le prendre en charge.
nir le
3
Citer la documentation n'est pas utile. Si la documentation était claire (assez? De la manière particulièrement nécessaire?) Alors la question ne serait pas nécessaire. Par exemple, dans ce cas, on ne sait vraiment pas comment config.locationet comment config.namesinteragir, bien que cela semble probablement clair pour les personnes qui savent déjà comment elles interagissent. Pouvez-vous mettre à jour votre réponse pour ajouter quelque chose à la documentation?
Narfanator
13
Cela devrait être mis à jour, car le comportement de spring.config.locationnow remplace la valeur par défaut au lieu d'y ajouter. Vous devez utiliser spring.config.additional-locationpour conserver les valeurs par défaut. Il s'agit d'un changement de comportement de 1.x à 2.x.
Robin
32

Avec Spring boot, le spring.config.location fonctionne, il suffit de fournir des fichiers de propriétés séparés par des virgules.

voir le code ci-dessous

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

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

on peut mettre la version par défaut de jdbc.properties dans l'application. Les versions externes peuvent être définies ici.

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

En fonction de la valeur du profil définie à l'aide de la propriété spring.profiles.active, la valeur de jdbc.host sera récupérée. Alors quand (sous Windows)

set spring.profiles.active=dev

jdbc.host prendra la valeur de jdbc-dev.properties.

pour

set spring.profiles.active=default

jdbc.host prendra la valeur de jdbc.properties.

ganesh jadhav
la source
Je ne pense pas que le premier des blocs de code fonctionnerait. Je sais que je me suis écrasé sur celui-ci et que j'ai suivi cette réponse . Voir jira.springsource.org/browse/SPR-8539 référencé dans la réponse pour une explication décente.
Sowka
27

Spring boot 1.X et Spring Boot 2.X ne fournissent pas les mêmes options et le même comportement sur le Externalized Configuration.

La très bonne réponse de M. Deinum fait référence aux spécificités de Spring Boot 1.
Je vais mettre à jour pour Spring Boot 2 ici.

Sources et ordre des propriétés de l'environnement

Spring Boot 2 utilise un PropertySourceordre très particulier conçu pour permettre le remplacement judicieux des valeurs. Les propriétés sont considérées dans l'ordre suivant:

  • Propriétés des paramètres globaux de Devtools sur votre répertoire personnel (~ / .spring-boot-devtools.properties lorsque devtools est actif).

  • @TestPropertySource annotations sur vos tests.

  • @SpringBootTest#propertiesattribut d'annotation sur vos tests. Arguments de ligne de commande.

  • Propriétés de SPRING_APPLICATION_JSON(JSON en ligne incorporé dans une variable d'environnement ou une propriété système).

  • ServletConfig paramètres init.

  • ServletContext paramètres init.

  • Attributs JNDI de java:comp/env.

  • Propriétés du système Java ( System.getProperties()).

  • Variables d'environnement du système d'exploitation.

  • Un RandomValuePropertySourcequi a des propriétés uniquement au hasard. *

  • Propriétés d'application spécifiques au profil en dehors de votre jar emballé ( application-{profile}.propertieset des variantes YAML).

  • Propriétés d'application spécifiques au profil intégrées à votre fichier jar ( application-{profile}.propertieset variantes YAML).

  • Propriétés de l'application en dehors de votre jar emballé ( application.propertieset des variantes YAML).

  • Propriétés de l'application emballées dans votre fichier jar ( application.propertieset variantes YAML).

  • @PropertySourceannotations sur vos @Configurationcours. Propriétés par défaut (spécifiées par le paramètre SpringApplication.setDefaultProperties).

Pour spécifier des fichiers de propriétés externes, ces options devraient vous intéresser:

  • Propriétés d'application spécifiques au profil en dehors de votre jar emballé ( application-{profile}.propertieset des variantes YAML).

  • Propriétés de l'application en dehors de votre jar emballé ( application.propertieset des variantes YAML).

  • @PropertySourceannotations sur vos @Configurationcours. Propriétés par défaut (spécifiées par le paramètre SpringApplication.setDefaultProperties).

Vous ne pouvez utiliser qu'une seule de ces 3 options ou les combiner selon vos besoins.
Par exemple, pour des cas très simples, il suffit d'utiliser uniquement des propriétés spécifiques au profil, mais dans d'autres cas, vous souhaiterez peut-être utiliser à la fois les propriétés spécifiques au profil, les propriétés par défaut et @PropertySource.

Emplacements par défaut des fichiers application.properties

À propos des application.propertiesfichiers (et des variantes), par défaut, Spring les charge et ajoute leurs propriétés dans l'environnement à partir de ceux-ci dans l'ordre suivant:

  • Un sous-répertoire / config du répertoire courant

  • Le répertoire courant

  • Un package classpath / config

  • La racine du chemin de classe

Les priorités plus élevées sont donc littéralement:
classpath:/,classpath:/config/,file:./,file:./config/.

Comment utiliser des fichiers de propriétés avec des noms spécifiques?

Les emplacements par défaut ne sont pas toujours suffisants: les emplacements par défaut comme le nom de fichier par défaut ( application.properties) peuvent ne pas convenir. En outre, comme dans la question OP, vous devrez peut-être spécifier plusieurs fichiers de configuration autres que application.properties(et variante).
Ce spring.config.namene sera donc pas suffisant.

Dans ce cas, vous devez fournir un emplacement explicite à l'aide de la spring.config.locationpropriété d'environnement (qui est une liste d'emplacement de répertoire ou de chemin de fichier séparés par des virgules).
Pour être libre sur le modèle des noms de fichiers, privilégiez la liste des chemins de fichiers sur la liste des répertoires.
Par exemple, faites comme ça:

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

C'est la manière la plus verbeuse que de spécifier simplement le dossier mais c'est aussi la manière de spécifier très finement nos fichiers de configuration et de documenter clairement les propriétés effectivement utilisées.

spring.config.location remplace désormais les emplacements par défaut au lieu de les ajouter

Avec Spring Boot 1, l' spring.config.locationargument ajoute des emplacements spécifiés dans l'environnement Spring.
Mais à partir de Spring Boot 2, spring.config.locationremplace les emplacements par défaut utilisés par Spring par les emplacements spécifiés dans l'environnement Spring, comme indiqué dans la documentation .

Lorsque les emplacements de configuration personnalisés sont configurés à l'aide de spring.config.location, ils remplacent les emplacements par défaut. Par exemple, si spring.config.locationest configuré avec la valeur classpath:/custom-config/, file:./custom-config/l'ordre de recherche devient la suivante:

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.locationest maintenant un moyen de s'assurer que tout application.propertiesfichier doit être spécifié explicitement.
Pour les JAR uber qui ne sont pas censés empaqueter des application.propertiesfichiers, c'est plutôt bien.

Pour conserver l'ancien comportement spring.config.locationlors de l'utilisation de Spring Boot 2, vous pouvez utiliser la nouvelle spring.config.additional-locationpropriété au lieu de spring.config.locationcela ajoute toujours les emplacements comme indiqué dans la documentation :

Sinon, lorsque les emplacements de configuration personnalisés sont configurés à l'aide de spring.config.additional-location, ils sont utilisés en plus des emplacements par défaut.


En pratique

Supposons donc que, comme dans la question OP, vous ayez 2 fichiers de propriétés externes à spécifier et 1 fichier de propriétés inclus dans le fichier uber jar.

Pour utiliser uniquement les fichiers de configuration que vous avez spécifiés:

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

Pour y ajouter des fichiers de configuration aux emplacements par défaut:

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

classpath:/applications.properties n'est pas nécessaire dans le dernier exemple car les emplacements par défaut l'ont et que les emplacements par défaut ne sont pas ici écrasés mais étendus.

davidxxx
la source
Votre réponse est vraiment complète, sauf sur un point: où Spring trouvera-t-il la configuration externe job1.properties sur le disque si vous spécifiez simplement: "classpath: /job1.properties"? Comment avez-vous ajouté votre répertoire contenant des propriétés externes au chemin de classe ici?
Tristan
@Tristan, en gros, spring peut en lire un application.propertiesavec tous les paramètres et plusieurs ${file_name}.propertiesavec des ensembles de propriétés partiellement définis. Donc, si vous utilisez @PropertySourceou d'autres liens forts vers des fichiers, vous pouvez créer un autre fichier externe et remplacer ces propriétés (par exemple: à partir de classpath:file.properties).
Mister_Jesus
23

Jetez un œil à PropertyPlaceholderConfigurer, je le trouve plus clair à utiliser que l'annotation.

par exemple

@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
la source
Merci beaucoup pour cette réponse. Pouvez-vous s'il vous plaît me faire savoir comment puis-je réaliser la même chose dans un projet qui a des configurations XML similaires pour différentes choses sans fichier XML de base? Votre réponse ci-dessus m'a aidé dans un autre projet basé sur des annotations. Merci encore pour cela.
Chetan
8

c'est une approche simple utilisant la botte à ressort

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

le contexte app.properties , à l' emplacement sélectionné

test.one = 1234

votre application Spring Boot

@SpringBootApplication

public class TestApplication {

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

et le contexte prédéfini application.properties

spring.profiles.active = one

vous pouvez écrire autant de classes de configuration que vous le souhaitez et les activer / désactiver simplement en définissant spring.profiles.active = le / les noms du profil {séparés par des virgules}

comme vous pouvez le voir, le démarrage du printemps est génial, il a juste besoin d'un certain temps pour se familiariser, il convient de mentionner que vous pouvez également utiliser @Value sur vos champs

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

J'ai eu le même problème. Je voulais avoir la possibilité d'écraser un fichier de configuration interne au démarrage par un fichier externe, similaire à la détection Spring Boot application.properties. Dans mon cas, c'est un fichier user.properties où sont stockés les utilisateurs de mes applications.

Mes exigences:

Chargez le fichier à partir des emplacements suivants (dans cet ordre)

  1. Le chemin des classes
  2. Un sous - répertoire / config du répertoire courant.
  3. Le répertoire courant
  4. Depuis un répertoire ou un emplacement de fichier donné par un paramètre de ligne de commande au démarrage

J'ai trouvé la solution suivante:

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

}

Maintenant, l'application utilise la ressource classpath, mais recherche également une ressource aux autres emplacements donnés. La dernière ressource existante sera sélectionnée et utilisée. Je suis capable de démarrer mon application avec java -jar myapp.jar --properties.location = / répertoire / myproperties.properties pour utiliser un emplacement de propriétés qui fait flotter mon bateau.

Un détail important ici: utilisez une chaîne vide comme valeur par défaut pour la propriété properties.location dans l'annotation @Value pour éviter les erreurs lorsque la propriété n'est pas définie.

La convention pour un properties.location est la suivante: Utilisez un répertoire ou un chemin vers un fichier de propriétés en tant que properties.location.

Si vous souhaitez remplacer uniquement des propriétés spécifiques, un PropertiesFactoryBean avec setIgnoreResourceNotFound (true) peut être utilisé avec le tableau de ressources défini comme emplacements.

Je suis sûr que cette solution peut être étendue pour gérer plusieurs fichiers ...

ÉDITER

Voici ma solution pour plusieurs fichiers :) Comme avant, cela peut être combiné avec 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;
    }

}
mxsb
la source
belle solution de contournement. Comme ça, java8 construit! de toute façon, je ne peux pas l'utiliser car j'ai besoin de plusieurs haricots Properties et non d'un seul. Si vous voyez mes modifications, ma solution de contournement est assez similaire et soignée pour mon cas d'utilisation.
nir
J'ai publié une version pour plusieurs fichiers, juste pour être complet;)
mxsb
6

spring boot nous permet d'écrire différents profils à écrire pour différents environnements, par exemple, nous pouvons avoir des fichiers de propriétés séparés pour les environnements de production, qa et locaux

Le fichier application-local.properties avec des configurations en fonction de ma machine locale est

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

De même, nous pouvons écrire application-prod.properties et application-qa.properties autant de fichiers de propriétés que nous le voulons

puis écrivez des scripts pour démarrer l'application pour différents environnements, par exemple

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod
Humble monstre
la source
5

J'ai juste eu un problème similaire à celui-ci et j'ai finalement trouvé la cause: le fichier application.properties avait les mauvais attributs de propriété et rwx. Ainsi, lorsque tomcat a démarré, le fichier application.properties était au bon endroit, mais appartenait à un autre utilisateur:

$ chmod 766 application.properties

$ chown tomcat application.properties
Robjwilkins
la source
Je pense que j'ai un problème similaire. J'ai installé tomcat dans le dossier opt. Où avez-vous placé votre dossier de candidature? Dois-je également modifier les attributs de dossier?
anakin59490
3

Une version modifiée de la solution @mxsb qui nous permet de définir plusieurs fichiers et dans mon cas ce sont des fichiers yml.

Dans mon application-dev.yml, j'ai ajouté cette configuration qui me permet d'injecter tous les yml contenant -dev.yml. Cela peut également être une liste de fichiers spécifiques. "classpath: /test/test.yml,classpath: /test2/test.yml"

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

Cela aide à obtenir une carte des propriétés.

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

Cependant, si comme dans mon cas, je voulais avoir à diviser les fichiers yml pour chaque profil, les charger et les injecter directement dans la configuration du ressort avant l'initialisation des beans.

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

... vous avez eu l'idée

Le composant est légèrement différent

@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
la source
3

Si vous souhaitez remplacer les valeurs spécifiées dans votre fichier application.properties, vous pouvez modifier votre profil actif pendant que vous exécutez votre application et créez un fichier de propriétés d'application pour le profil. Ainsi, par exemple, spécifions le profil actif "override", puis, en supposant que vous ayez créé votre nouveau fichier de propriétés d'application appelé "application-override.properties" sous / tmp, alors vous pouvez exécuter

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

Les valeurs spécifiées sous spring.config.location sont évaluées dans l'ordre inverse. Ainsi, dans mon exemple, le classpat est évalué en premier, puis la valeur du fichier.

Si le fichier jar et le fichier "application-override.properties" se trouvent dans le répertoire courant, vous pouvez en fait simplement utiliser

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

puisque Spring Boot trouvera le fichier de propriétés pour vous

acaruci
la source
1
Il indiquera à Spring d'utiliser le profil "override" comme profil actif; il
dépasserait en
il cherchera à l'intérieur du dossier pour tout fichier de configuration .ymal ou .properties dans mon cas je mets seulement application-profile.yml alors il prend correctement, Merci @acaruci c'était un beau voyage
Ahmed Salem
0

J'ai trouvé que c'était un modèle utile à suivre:

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

Ici, nous remplaçons l'utilisation de "application.yml" pour utiliser "application-MyTest_LowerImportance.yml" et aussi "application-MyTest_MostImportant.yml"
(Spring recherchera également les fichiers .properties)

Les paramètres de débogage et de trace sont également inclus en tant que bonus supplémentaire, sur une ligne séparée afin que vous puissiez les commenter si nécessaire;]

Le débogage / trace est incroyablement utile car Spring videra les noms de tous les fichiers qu'il charge et ceux qu'il essaie de charger.
Vous verrez des lignes comme celle-ci dans la console au moment de l'exécution:

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
la source
-1

J'ai rencontré beaucoup de problèmes en essayant de comprendre cela. Voici ma configuration,

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

Ce que j'ai trouvé, c'est que le ressort s'en tient au concept "par défaut sensible pour la configuration". Cela se traduit par le fait que vous devez avoir tous vos fichiers de propriété dans votre fichier de guerre. Une fois là-dedans, vous pouvez les remplacer en utilisant la propriété de ligne de commande "--spring.config.additional-location" pour pointer vers des fichiers de propriétés externes. Mais cela ne fonctionnera PAS si les fichiers de propriétés ne font pas partie du fichier war d'origine.

Code démo: https://github.com/gselvara/spring-boot-property-demo/tree/master

Gselvara
la source