Aller au contenu principal

Variables d'environnement

Variables d'environnement et fichier de propriétés

Notions théoriques

Pourquoi ne pas mettre les mots de passe dans le code ?

Ne jamais stocker de secrets dans le code source

Mettre un mot de passe ou une clé d'API directement dans le code Java est une erreur grave. Si vous commitez ce fichier dans Git, le secret est exposé pour toujours dans l'historique, même si vous le supprimez dans un commit suivant.

// MAUVAIS - ne jamais faire ça !
String password = "monMotDePasseSecret123";

Il existe deux approches pour externaliser les données sensibles :

  1. Variables d'environnement : définies au niveau du système d'exploitation ou du serveur
  2. Fichier de propriétés : fichier .properties exclu du versionnement Git

Variables d'environnement avec System.getenv()

Les variables d'environnement sont des paires clé-valeur définies au niveau du système d'exploitation. Java les lit avec System.getenv() :

// Lire une variable d'environnement
String dbPassword = System.getenv("DB_PASSWORD");

if (dbPassword == null) {
System.out.println("Variable DB_PASSWORD non définie !");
} else {
System.out.println("Mot de passe lu depuis l'environnement.");
}

Définir une variable d'environnement dans IntelliJ (pour le développement) :

  1. Run > Edit Configurations...
  2. Sélectionnez votre configuration de lancement
  3. Dans le champ Environment variables, ajoute DB_PASSWORD=monMotDePasse

En production (serveur), les variables d'environnement sont définies au niveau du système ou du conteneur Docker.

Fichier config.properties

Un fichier .properties est un fichier texte de paires clé=valeur. Il doit être placé dans src/main/resources/ pour être accessible depuis le code Java, et exclu de Git via .gitignore.

Fichier src/main/resources/config.properties :

db.host=localhost
db.port=3306
db.name=ma_base
db.user=root
db.password=monMotDePasse

Lecture en Java avec la classe Properties :

import java.io.InputStream;
import java.util.Properties;

public class Config {

public static Properties charger() throws Exception {
Properties props = new Properties();
// Charger depuis le classpath (src/main/resources/)
InputStream input = Config.class.getResourceAsStream("/config.properties");
if (input == null) {
throw new Exception("Fichier config.properties introuvable");
}
props.load(input);
return props;
}

public static void main(String[] args) throws Exception {
Properties config = charger();
String host = config.getProperty("db.host");
String user = config.getProperty("db.user");
System.out.println("Connexion à " + host + " en tant que " + user);
}
}

.gitignore pour les fichiers de propriétés

Ajoute le fichier de configuration dans .gitignore pour ne pas le versionner :

# Fichiers de configuration avec secrets
src/main/resources/config.properties

Fournis à la place un fichier exemple sans les vraies valeurs :

# config.properties.example — copier en config.properties et remplir
db.host=localhost
db.port=3306
db.name=
db.user=
db.password=
Bonne pratique d'équipe

Versionne config.properties.example (sans secrets) et documente dans le README que les développeurs doivent copier ce fichier en config.properties et le remplir. Ne versionne jamais config.properties lui-même.

Maven Resources Filtering

Maven peut automatiquement remplacer des variables dans les fichiers de ressources lors du build. En activant le filtering dans pom.xml, on peut injecter des propriétés Maven dans les fichiers .properties :

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>

Puis dans config.properties :

app.version=${project.version}

Cette valeur sera remplacée par la version définie dans le pom.xml lors du build.

Exemple pratique

import java.io.InputStream;
import java.util.Properties;

public class ConfigurationApp {

public static void main(String[] args) {
// Approche 1 : variables d'environnement
String apiKey = System.getenv("API_KEY");
if (apiKey == null) {
System.out.println("Variable API_KEY non trouvée, utilisation de la valeur par défaut.");
apiKey = "cle-dev-locale";
}
System.out.println("API Key : " + apiKey.substring(0, 3) + "...");

// Approche 2 : fichier de propriétés
try {
Properties config = new Properties();
InputStream input = ConfigurationApp.class.getResourceAsStream("/config.properties");
if (input != null) {
config.load(input);
String host = config.getProperty("db.host", "localhost");
String port = config.getProperty("db.port", "3306");
System.out.println("Base de données : " + host + ":" + port);
} else {
System.out.println("config.properties introuvable, utilisation des valeurs par défaut.");
}
} catch (Exception e) {
System.out.println("Erreur chargement config : " + e.getMessage());
}
}
}
astuce

config.getProperty("cle", "valeurParDefaut") retourne la valeur par défaut si la clé n'existe pas. C'est utile pour rendre votre application fonctionnelle même sans fichier de configuration.

Test de mémorisation/compréhension


Quelle méthode Java lit une variable d'environnement ?


Pourquoi ne faut-il jamais mettre un mot de passe directement dans le code Java ?


Dans quel dossier Maven place-t-on le fichier config.properties pour qu'il soit accessible depuis le code ?


Quelle classe Java permet de charger et lire un fichier .properties ?


Que faut-il versionner à la place du fichier config.properties (avec secrets) ?


Comment définit-on des variables d'environnement pour une application dans IntelliJ ?


TP pour réfléchir et résoudre des problèmes

Vous allez créer un système de configuration qui lit les paramètres depuis un fichier .properties et depuis des variables d'environnement.

Étape 1 — Créer le fichier config.properties

Crée le fichier src/main/resources/config.properties avec les paramètres de base de données.


Bonne pratique - Nommer les clés avec des points

La convention pour les clés dans un fichier .properties est d'utiliser des points pour hiérarchiser : db.host, db.port, app.name, mail.smtp.host. Cela simule une arborescence et rend le fichier plus lisible.

Étape 2 — Charger et lire le fichier properties

Dans une méthode statique, charge le fichier et retourne un objet Properties.


Bonne pratique - Lancer une exception si le fichier est absent

Si le fichier de configuration est obligatoire, mieux vaut lancer une exception explicite (throw new Exception(...)) plutôt que de continuer silencieusement avec des valeurs nulles, ce qui provoquerait des erreurs difficiles à diagnostiquer plus tard.

Étape 3 — Fusionner variables d'environnement et properties

Les variables d'environnement doivent avoir la priorité sur le fichier de propriétés (utile pour les surcharges en production).


Bonne pratique - Variables d'environnement prioritaires sur le fichier

En production, les variables d'environnement (définies par l'administrateur ou le conteneur) doivent toujours avoir la priorité sur les fichiers de configuration. Ce pattern "env > fichier > valeur par défaut" est standard dans les applications modernes (12-Factor App).

📌 Une solution