web-dev-qa-db-fra.com

Utilisation de la variable env dans le fichier application.properties de Spring Boot

Nous travaillons sur une application Web Spring Boot et la base de données que nous utilisons est MySql;

  • la configuration que nous avons est la première chose à faire localement (cela signifie que nous devons installer MySql sur notre PC);

  • alors nous Push to Bitbucket;

  • Jenkins détecte automatiquement le nouveau Push to Bitbucket et le construit (pour que Jenkins mvn build passe, nous devons également installer MySql sur les machines virtuelles qui exécutent Jenkins).

  • si Jenkins réussit, nous envoyons le code à notre application sur OpenShift (à l'aide du plug-in de déploiement Openshift sur Jenkins).

Le problème que nous avons , comme vous l'avez peut-être déjà compris, est que:

  • dans application.properties nous ne pouvons pas coder en dur les informations MySql. Depuis notre projet sera en cours d'exécution dans 3 endroits différents ( local , Jenkins , et OpenShift ) nous devons rendre le champ de source de données dynamique dans application.properties (nous savons qu'il existe différentes façons de le faire, mais nous travaillons sur cette solution pour le moment).

    spring.datasource.url = 
    spring.datasource.username = 
    spring.datasource.password = 
    

La solution que nous avons trouvée est de créer des variables d’environnement système localement et dans Jenkins vm (en les nommant de la même manière que OpenShift les nomme) et en leur affectant le bonnes valeurs respectivement:

export OPENSHIFT_MYSQL_DB_Host="jdbc:mysql://localhost"
export OPENSHIFT_MYSQL_DB_PORT="3306"
export OPENSHIFT_MYSQL_DB_USERNAME="root"
export OPENSHIFT_MYSQL_DB_PASSWORD="123asd"

Nous avons fait cela et ça marche. Nous avons également vérifié avec Map<String, String> env = System.getenv(); que les variables d'environnement peuvent être transformées en Java variables en tant que telles:

String password = env.get("OPENSHIFT_MYSQL_DB_PASSWORD");   
String userName = env.get("OPENSHIFT_MYSQL_DB_USERNAME");   
String sqlURL = env.get("OPENSHIFT_MYSQL_DB_Host"); 
String sqlPort = env.get("OPENSHIFT_MYSQL_DB_PORT");

Il ne nous reste plus qu’à utiliser ces variables Java dans notre application.properties et c’est ce qui nous pose problème.

Dans quel dossier et comment devons-nous affecter les variables password, userName, sqlURL et sqlPort pour application.properties afin de pouvoir les afficher et comment pouvons-nous les inclure dans application.properties?

Nous avons essayé beaucoup de choses, l'une d'entre elles étant:

spring.datasource.url = ${sqlURL}:${sqlPort}/"nameofDB"
spring.datasource.username = ${userName}
spring.datasource.password = ${password}

Pas de chance jusqu'à présent. Nous ne mettons probablement pas ces variables env dans la bonne classe/le bon dossier ou ne les utilisons pas correctement dans application.properties.

Votre aide est très appréciée!!

Merci!

134
S M

Vous n'avez pas besoin d'utiliser les variables Java. Pour inclure les variables d’environnement système, ajoutez ce qui suit dans votre fichier application.properties:

spring.datasource.url = ${OPENSHIFT_MYSQL_DB_Host}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB"
spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME}
spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PASSWORD}

Mais la manière suggérée par @ Stefan Isele est préférable, car dans ce cas, vous ne devez déclarer qu'une seule variable env: spring.profiles.active. Spring lira automatiquement le fichier de propriétés approprié selon le modèle application-{profile-name}.properties.

158
Ken Bekov

Le moyen le plus simple d’avoir différentes configurations pour différents environnements est d’utiliser des profils de ressort. Voir configuration externalisée .

Cela vous donne beaucoup de flexibilité. Je l'utilise dans mes projets et c'est extrêmement utile. Dans votre cas, vous auriez 3 profils: "local", "jenkins" et "openshift"

Vous avez alors 3 fichiers de propriétés spécifiques au profil: application-local.properties, application-jenkins.properties et application-openshift.properties

Là, vous pouvez définir les propriétés pour l'environnement concerné. Lorsque vous exécutez l'application, vous devez spécifier le profil à activer comme suit: -Dspring.profiles.active=jenkins

Modifier

Selon la documentation print, vous pouvez définir la variable d'environnement système SPRING_PROFILES_ACTIVE pour activer les profils. Il n'est pas nécessaire de la transmettre en tant que paramètre.

Y a-t-il un moyen de passer l'option de profil actif pour l'application Web au moment de l'exécution?

Non, Spring détermine les profils actifs lors de la création du contexte d'application. Les profils actifs sont ensuite utilisés pour décider quels fichiers de propriétés sont lus et quels beans sont instanciés. Une fois l'application lancée, cela ne peut plus être changé.

Ceci est en réponse à un certain nombre de commentaires car ma réputation n'est pas assez élevée pour commenter directement.

Vous pouvez spécifier le profil au moment de l'exécution tant que le contexte de l'application n'a pas encore été chargé.

// Previous answers incorrectly used "spring.active.profiles" instead of
// "spring.profiles.active" (as noted in the comments).
// Use AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME to avoid this mistake.

System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, environment);
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml");
8
gthazmatt

Flayway ne reconnaît pas les variables d’environnement directes dans le fichier application.properties (Spring-Boot V2.1). par exemple

spring.datasource.url=jdbc:mysql://${DB_HOSTNAME}:${DB_PORT}/${DB_DATABASE}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASS}

Pour résoudre ce problème, j'ai créé les variables d'environnement. Généralement, je crée le fichier .env:

SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/place
SPRING_DATASOURCE_USERNAME=root
SPRING_DATASOURCE_PASSWORD=root

Et exportez les variables dans mon environnement:

export $(cat .env | xargs)

Et enfin, lancez la commande

mvn spring-boot:run

Ou lancez votre fichier jar

Java -jar target/your-file.jar

Il existe une autre approche ici: https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/maven-plugin/examples/run-env-variables.html

5
Felipe Girotti

Here est un code de fragment tiré d'une chaîne d'environnements, les fichiers de propriétés étant chargés pour différents environnements.

Fichier de propriétés sous les ressources de votre application ( src/main/resources ): -

 1. application.properties
 2. application-dev.properties
 3. application-uat.properties
 4. application-prod.properties

Idéalement, application.properties contient toutes les propriétés communes accessibles pour tous les environnements et les propriétés liées à l'environnement ne fonctionnent que sur l'environnement spécifié. Par conséquent, l'ordre de chargement de ces fichiers de propriétés sera le suivant:

 application.properties -> application.{spring.profiles.active}.properties.

Extrait de code ici: -

    import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;

    public class PropertiesUtils {

        public static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";

        public static void initProperties() {
            String activeProfile = System.getProperty(SPRING_PROFILES_ACTIVE);
            if (activeProfile == null) {
                activeProfile = "dev";
            }
            PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer
                    = new PropertySourcesPlaceholderConfigurer();
            Resource[] resources = new ClassPathResource[]
                    {new ClassPathResource("application.properties"),
                            new ClassPathResource("application-" + activeProfile + ".properties")};
            propertySourcesPlaceholderConfigurer.setLocations(resources);

        }
    }
5
Ajay Kumar

Utilisation du contexte Spring 5.0 J'ai réussi à charger le fichier de propriétés correct en fonction de l'environnement du système via l'annotation suivante

@PropertySources({
    @PropertySource("classpath:application.properties"),
    @PropertySource("classpath:application-${MYENV:test}.properties")})

Ici, la valeur MYENV est lue à partir de l’environnement système. Si l’environnement système n’est pas présent, le fichier de propriétés de l’environnement de test par défaut est chargé. Si je spécifie une valeur MYENV erronée, l’application ne pourra pas démarrer.

Remarque: pour chaque profil, vous souhaitez conserver - vous devrez créer un fichier application- [profil] .property et même si j'ai utilisé Spring context 5.0 et non Spring Boot - je crois que cela fonctionnera également. sur le printemps 4.1

2

J'écris peut-être cela trop tard, mais le problème est similaire lorsque j'ai essayé de remplacer les méthodes de lecture des propriétés.

Mon problème a été le suivant: 1) Lire une propriété à partir d'env si cette propriété a été définie dans env. 2) Lire une propriété à partir de la propriété système si cette propriété a été définie dans la propriété système 3). Enfin, lisez à partir des propriétés de l'application.

Donc, pour résoudre ce problème, je vais dans ma classe de configuration de bean

@Validated
@Configuration
@ConfigurationProperties(prefix = ApplicationConfiguration.PREFIX)
@PropertySource(value = "${application.properties.path}", factory = PropertySourceFactoryCustom.class)
@Data // lombok
public class ApplicationConfiguration {

    static final String PREFIX = "application";

    @NotBlank
    private String keysPath;

    @NotBlank
    private String publicKeyName;

    @NotNull
    private Long tokenTimeout;

    private Boolean devMode;

    public void setKeysPath(String keysPath) {
        this.keysPath = StringUtils.cleanPath(keysPath);
    }
}

Et écraser l'usine dans @PropertySource. Et puis j'ai créé ma propre implémentation pour la lecture des propriétés.

    public class PropertySourceFactoryCustom implements PropertySourceFactory {

        @Override
        public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
            return name != null ? new PropertySourceCustom(name, resource) : new PropertySourceCustom(resource);
        }


    }

Et créé PropertySourceCustom

public class PropertySourceCustom extends ResourcePropertySource {


    public LifeSourcePropertySource(String name, EncodedResource resource) throws IOException {
        super(name, resource);
    }

    public LifeSourcePropertySource(EncodedResource resource) throws IOException {
        super(resource);
    }

    public LifeSourcePropertySource(String name, Resource resource) throws IOException {
        super(name, resource);
    }

    public LifeSourcePropertySource(Resource resource) throws IOException {
        super(resource);
    }

    public LifeSourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException {
        super(name, location, classLoader);
    }

    public LifeSourcePropertySource(String location, ClassLoader classLoader) throws IOException {
        super(location, classLoader);
    }

    public LifeSourcePropertySource(String name, String location) throws IOException {
        super(name, location);
    }

    public LifeSourcePropertySource(String location) throws IOException {
        super(location);
    }

    @Override
    public Object getProperty(String name) {

        if (StringUtils.isNotBlank(System.getenv(name)))
            return System.getenv(name);

        if (StringUtils.isNotBlank(System.getProperty(name)))
            return System.getProperty(name);

        return super.getProperty(name);
    }
}

Donc, cela m'a aidé.

2
Maksym Galich

J'ai rencontré le même problème que l'auteur de la question. Dans notre cas, les réponses à cette question n’étaient pas suffisantes, car chacun des membres de mon équipe disposait d’un environnement local différent et nous avions donc absolument besoin de .gitignore le fichier contenant la chaîne de connexion à la base de données et les informations d’identité différentes, afin que les utilisateurs ne t commettez le fichier commun par erreur et coupez les connexions à la base de données des autres.

De plus, lorsque nous avons suivi la procédure ci-dessous, il était facile à déployer sur différents environnements et, en tant que bonus supplémentaire , nous n’avions pas du tout besoin d’informations sensibles dans le contrôle de version .

Obtenir l'idée de PHP Framework Symfony 3 qui a un parameters.yml (.gitignored) et un parameters.yml.dist (qui est un exemple qui crée le premier via composer install) ,

J'ai fait ce qui suit en combinant les connaissances des réponses ci-dessous: https://stackoverflow.com/a/35534970/98616 et https://stackoverflow.com/a/35535138/98616 .

Essentiellement, cela donne la liberté d'utiliser héritage des configurations de ressort et de choisir les profils actifs via la configuration du haut, ainsi que les informations d'identification supplémentaires sensibles, comme suit:

application.yml.dist (exemple)

    spring:
      profiles:
        active: local/dev/prod
      datasource:
        username:
        password:
        url: jdbc:mysql://localhost:3306/db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application.yml (.gitignore-d sur un serveur de développement)

spring:
  profiles:
    active: dev
  datasource:
    username: root
    password: verysecretpassword
    url: jdbc:mysql://localhost:3306/real_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application.yml (.gitignore-d sur une machine locale)

spring:
  profiles:
    active: local
  datasource:
    username: root
    password: rootroot
    url: jdbc:mysql://localhost:3306/xampp_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application-dev.yml (propriétés spécifiques à l'environnement non sensibles)

spring:
  datasource:
    testWhileIdle: true
    validationQuery: SELECT 1
  jpa:
    show-sql: true
    format-sql: true
    hibernate:
      ddl-auto: create-droop
      naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL57InnoDBDialect

Même chose peut être fait avec .properties

1