TP5.3 - Configuration par Profils
Objectifs
À la fin de ce TP, vous serez capable de:
- ✅ Créer des profils pour dev, test, et prod
- ✅ Créer des Beans conditionnels selon le profil
- ✅ Utiliser des fichiers
application-\{profile\}.properties - ✅ Activer un profil et tester
Durée estimée: 1h30
Prérequis
- ✅ Chapitre 4 du Module 5 complété
- ✅ TP5.1 et TP5.2 complétés
- ✅ Maven 3.9+ et Java 17+
Préparation: Nouveau Projet
Créer le Projet
Via Spring Initializr:
- Project: Maven
- Spring Boot: 3.2.0
- Artifact:
profiles-demo - Dependencies: Spring Web, Spring Data JPA, H2 Database, PostgreSQL Driver
Structure:
src/main/java/com/example/profiles/
├── ProfilesDemoApplication.java
├── service/
│ ├── EmailService.java
│ ├── FakeEmailService.java
│ └── SmtpEmailService.java
├── config/
│ ├── DevConfig.java
│ ├── ProdConfig.java
│ └── DatabaseConfig.java
└── controller/
└── TestController.java
src/main/resources/
├── application.properties
├── application-dev.properties
├── application-test.properties
└── application-prod.properties
Exercice 1: Profils pour Services Email
Objectif
Créer 2 implémentations d'EmailService: une fake pour dev, une réelle pour prod.
Étape 1.1: Créer l'Interface
Fichier: service/EmailService.java
package com.example.profiles.service;
public interface EmailService {
void send(String to, String subject, String body);
}
Étape 1.2: Implémentation DEV (Fake)
Fichier: service/FakeEmailService.java
package com.example.profiles.service;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@Service
@Profile("dev") // ← Actif SEULEMENT en dev
public class FakeEmailService implements EmailService {
@Override
public void send(String to, String subject, String body) {
System.out.println("========== FAKE EMAIL ==========");
System.out.println("To: " + to);
System.out.println("Subject: " + subject);
System.out.println("Body: " + body);
System.out.println("================================");
System.out.println("(Email simulé - pas envoyé réellement)");
}
}
Points clés:
@Profile("dev")→ Bean créé seulement en profil dev- Email simulé → Pas de vrai envoi
Étape 1.3: Implémentation PROD (Réelle)
Fichier: service/SmtpEmailService.java
package com.example.profiles.service;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@Service
@Profile("prod") // ← Actif SEULEMENT en prod
public class SmtpEmailService implements EmailService {
@Override
public void send(String to, String subject, String body) {
System.out.println("========== SMTP EMAIL ==========");
System.out.println("Connexion au serveur SMTP...");
System.out.println("Authentification...");
System.out.println("Envoi à: " + to);
System.out.println("Sujet: " + subject);
System.out.println("================================");
System.out.println("(Email réellement envoyé)");
// En production, ici vous utiliseriez JavaMail:
// Session session = Session.getInstance(properties, authenticator);
// MimeMessage message = new MimeMessage(session);
// Transport.send(message);
}
}
Étape 1.4: Créer le Controller de Test
Fichier: controller/TestController.java
package com.example.profiles.controller;
import com.example.profiles.service.EmailService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/test")
public class TestController {
private final EmailService emailService;
@Value("${spring.profiles.active:default}")
private String activeProfile;
public TestController(EmailService emailService) {
this.emailService = emailService;
}
@GetMapping("/email")
public String testEmail() {
emailService.send(
"user@example.com",
"Test Email",
"Ceci est un email de test"
);
return "✅ Email envoyé via profil: " + activeProfile +
" - Voir console";
}
@GetMapping("/profile")
public String getActiveProfile() {
return "Profil actif: " + activeProfile;
}
}
Étape 1.5: Activer le Profil DEV
Fichier: src/main/resources/application.properties
# Profil actif
spring.profiles.active=dev
# Nom de l'application
spring.application.name=Profiles Demo
Étape 1.6: Tester en DEV
Démarrez:
mvn clean install -DskipTests spring-boot:run
Console au démarrage:
The following 1 profile is active: "dev"
Testez:
http://localhost:8080/api/test/email
Console:
========== FAKE EMAIL ==========
To: user@example.com
Subject: Test Email
Body: Ceci est un email de test
================================
(Email simulé - pas envoyé réellement)
✅ En DEV: Email simulé!
Étape 1.7: Tester en PROD
Modifiez application.properties:
spring.profiles.active=prod
Redémarrez et testez:
Console:
The following 1 profile is active: "prod"
========== SMTP EMAIL ==========
Connexion au serveur SMTP...
Authentification...
Envoi à: user@example.com
Sujet: Test Email
================================
(Email réellement envoyé)
✅ En PROD: Email réel!
Exercice 2: Configuration Base de Données par Profil
Objectif
Utiliser H2 en dev/test, PostgreSQL en prod.
Étape 2.1: Fichier application.properties (Commun)
Fichier: src/main/resources/application.properties
# Profil actif (changez selon besoin)
spring.profiles.active=dev
# Configuration commune
spring.application.name=Profiles Demo
server.port=8080
# JPA commun
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
Étape 2.2: Configuration DEV (H2)
Fichier: src/main/resources/application-dev.properties
# Base de données H2 en mémoire
spring.datasource.url=jdbc:h2:mem:devdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
# Console H2
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
# Hibernate
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Logs
logging.level.root=DEBUG
logging.level.com.example.profiles=DEBUG
Étape 2.3: Configuration TEST (H2 avec scripts)
Fichier: src/main/resources/application-test.properties
# Base de données H2 en mémoire pour tests
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
# Hibernate
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Logs minimaux pour tests
logging.level.root=WARN
logging.level.com.example.profiles=INFO
Étape 2.4: Configuration PROD (PostgreSQL)
Fichier: src/main/resources/application-prod.properties
# Base de données PostgreSQL
spring.datasource.url=jdbc:postgresql://localhost:5432/proddb
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=admin
spring.datasource.password=admin123
# Hibernate
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
# Logs minimaux
logging.level.root=WARN
logging.level.com.example.profiles=INFO
# Sécurité (en production, utilisez des variables d'environnement!)
# spring.datasource.username=${DB_USERNAME}
# spring.datasource.password=${DB_PASSWORD}
Étape 2.5: Créer une Entité de Test
Fichier: model/User.java
package com.example.profiles.model;
import jakarta.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// Constructeurs
public User() {}
public User(String name, String email) {
this.name = name;
this.email = email;
}
// Getters et Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
Étape 2.6: Tester les Différentes BDs
En DEV (H2):
spring.profiles.active=dev
Démarrez et vérifiez la console:
H2 console available at '/h2-console'
Hibernate: create table users (...)
Database: H2
Accédez à la console H2:
http://localhost:8080/h2-console
JDBC URL: jdbc:h2:mem:devdb
Username: sa
Password: (vide)
En PROD (PostgreSQL):
- Créez d'abord la base:
CREATE DATABASE proddb;
- Modifiez le profil:
spring.profiles.active=prod
- Démarrez:
Database: PostgreSQL
Hibernate: validate schema
Exercice 3: Beans de Configuration par Profil
Objectif
Créer des Beans différents selon l'environnement.
Étape 3.1: Configuration DEV
Fichier: config/DevConfig.java
package com.example.profiles.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
@Profile("dev") // ← Toute la classe active en dev
public class DevConfig {
@Bean
public String environmentName() {
return "DEVELOPMENT";
}
@Bean
public boolean debugMode() {
return true;
}
@Bean
public String apiUrl() {
return "http://localhost:8080/api";
}
}
Étape 3.2: Configuration PROD
Fichier: config/ProdConfig.java
package com.example.profiles.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
@Profile("prod") // ← Toute la classe active en prod
public class ProdConfig {
@Bean
public String environmentName() {
return "PRODUCTION";
}
@Bean
public boolean debugMode() {
return false;
}
@Bean
public String apiUrl() {
return "https://api.monsite.com/api";
}
}
Étape 3.3: Tester
Ajoutez dans TestController.java:
@RestController
@RequestMapping("/api/test")
public class TestController {
private final EmailService emailService;
private final String environmentName;
private final boolean debugMode;
private final String apiUrl;
@Value("${spring.profiles.active:default}")
private String activeProfile;
public TestController(
EmailService emailService,
String environmentName,
boolean debugMode,
String apiUrl
) {
this.emailService = emailService;
this.environmentName = environmentName;
this.debugMode = debugMode;
this.apiUrl = apiUrl;
}
// ... autres méthodes ...
@GetMapping("/config")
public String getConfig() {
return String.format(
"Environnement: %s<br>" +
"Profil actif: %s<br>" +
"Mode debug: %s<br>" +
"API URL: %s",
environmentName,
activeProfile,
debugMode,
apiUrl
);
}
}
En DEV:
Environnement: DEVELOPMENT
Profil actif: dev
Mode debug: true
API URL: http://localhost:8080/api
En PROD:
Environnement: PRODUCTION
Profil actif: prod
Mode debug: false
API URL: https://api.monsite.com/api
Exercice 4: Profils Multiples et @Profile Composé
Objectif
Activer plusieurs profils et créer des conditions complexes.
Étape 4.1: Bean pour Plusieurs Profils
Ajoutez dans config/DevConfig.java:
@Bean
@Profile({"dev", "test"}) // ← Actif en dev OU test
public String sharedDevTestBean() {
return "Bean partagé entre dev et test";
}
Étape 4.2: Bean Conditionnel Complexe
@Bean
@Profile("!prod") // ← Actif dans TOUS les profils SAUF prod
public String nonProdBean() {
return "Bean pour non-production (dev, test, etc.)";
}
Étape 4.3: Activer Plusieurs Profils
Méthode 1: application.properties
spring.profiles.active=dev,mock-data,debug
Méthode 2: Ligne de commande
mvn spring-boot:run -Dspring-boot.run.profiles=dev,mock-data
Méthode 3: Variable d'environnement
export SPRING_PROFILES_ACTIVE=prod,monitoring
mvn spring-boot:run
Exercice 5: Configuration Complète Multi-Environnements
Objectif
Créer une configuration production-ready.
Étape 5.1: Variables d'Environnement en PROD
Fichier: application-prod.properties
# Base de données (depuis variables d'environnement)
spring.datasource.url=${DATABASE_URL:jdbc:postgresql://localhost:5432/proddb}
spring.datasource.username=${DB_USERNAME:admin}
spring.datasource.password=${DB_PASSWORD}
# SMTP (depuis variables d'environnement)
spring.mail.host=${SMTP_HOST:smtp.gmail.com}
spring.mail.port=${SMTP_PORT:587}
spring.mail.username=${SMTP_USERNAME}
spring.mail.password=${SMTP_PASSWORD}
# API Keys
app.external-api.key=${EXTERNAL_API_KEY}
app.external-api.url=${EXTERNAL_API_URL:https://api.service.com}
Syntaxe:
$\{VAR_NAME\}→ Variable obligatoire (erreur si absente)${VAR_NAME:default}→ Variable avec valeur par défaut
Étape 5.2: Déployer avec Variables
Linux/Mac:
export DATABASE_URL="jdbc:postgresql://prod-server:5432/myapp"
export DB_USERNAME="app_user"
export DB_PASSWORD="secret123"
export SMTP_USERNAME="noreply@myapp.com"
export SMTP_PASSWORD="smtp_secret"
mvn spring-boot:run
Windows:
$env:DATABASE_URL="jdbc:postgresql://prod-server:5432/myapp"
$env:DB_USERNAME="app_user"
# ...
mvn spring-boot:run
Récapitulatif
Structure des Fichiers
application.properties ← Configuration commune
application-dev.properties ← Spécifique dev
application-test.properties ← Spécifique test
application-prod.properties ← Spécifique prod
Ordre de priorité:
1. application-{profile}.properties (spécifique)
2. application.properties (commune)
3. Variables d'environnement
4. Arguments ligne de commande
Beans par Profil
// Bean pour UN profil
@Profile("dev")
// Bean pour PLUSIEURS profils
@Profile({"dev", "test"})
// Bean pour TOUS sauf un
@Profile("!prod")
// Classe entière
@Configuration
@Profile("dev")
public class DevConfig { }
Activer un Profil
1. application.properties:
spring.profiles.active=dev
2. Ligne de commande:
--spring.profiles.active=prod
3. Variable d'environnement:
export SPRING_PROFILES_ACTIVE=prod
4. IDE (VS Code):
"spring.profiles.active": "dev"
Auto-Évaluation
- Quelle est la différence entre application.properties et application-dev.properties?
- Comment créer un Bean actif seulement en dev?
- Comment activer plusieurs profils simultanément?
- Pourquoi utiliser des variables d'environnement en production?
- Quelle est la syntaxe pour une variable avec valeur par défaut?
Challenge Bonus 🎯
Créez une configuration complète pour une vraie application:
-
3 profils: dev, test, prod
-
Dev:
- H2 en mémoire
- Email fake
- Logs DEBUG
- Pas de sécurité
-
Test:
- H2 avec scripts
- Email mock
- Logs INFO
-
Prod:
- PostgreSQL
- Email SMTP réel
- Logs WARN
- Sécurité activée
- Variables d'environnement
Bonus: Ajoutez un profil docker pour Docker Compose
Félicitations! 🎉
Vous avez terminé le Module 5!
Vous maîtrisez maintenant:
- ✅ Inversion de Contrôle (IoC)
- ✅ Injection de Dépendances (DI)
- ✅ Beans et leur cycle de vie
- ✅ Scopes (Singleton, Prototype)
- ✅ Configuration par profils
- ✅ Multi-environnements (dev/test/prod)
Vous êtes prêt pour des concepts avancés!