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 ?
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 :
- Variables d'environnement : définies au niveau du système d'exploitation ou du serveur
- Fichier de propriétés : fichier
.propertiesexclu 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) :
- Run > Edit Configurations...
- Sélectionnez votre configuration de lancement
- 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=
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());
}
}
}
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
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.
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.
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).
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).