☕ Spring Boot – Le Guide Ultime
Deep Dive : Convention/Config, DI (IoC), Starters, Web API (REST), Data JPA & Actuator.
1. C'est quoi Spring Boot ?
Framework Java "opinioné" (Convention > Config). "Just run". Serveur (Tomcat) embarqué.
Java Opinionated2. 💉 Cœur : DI & IoC
Inversion de Contrôle. @Autowired (Injection), @Component (Bean), ApplicationContext.
3. Starters & Auto-Config
La "magie". spring-boot-starter-web. pom.xml (Maven). Auto-configuration.
4. Configuration (.yml)
application.properties vs .yml. @Value, @ConfigurationProperties.
5. Framework : Web API (REST)
@RestController, @GetMapping, @PostMapping, @RequestBody, @PathVariable.
6. Framework : MVC
@Controller (vs Rest), Model. Templates (Thymeleaf vs JSP).
7. 💾 Data : Spring Data JPA
L'ORM "magique". @Entity, JpaRepository, Queries (findBy...), @Query (JPQL).
8. Plugin : Spring Security
SecurityFilterChain (@Bean). JWT vs Session. @PreAuthorize.
9. Plugin : Testing
@SpringBootTest (Intégration) vs @WebMvcTest (Slice). MockMvc, @MockBean.
10. Plugin : Actuator
Monitoring. Endpoints (/actuator/health, /metrics, /info). Prêt pour la prod.
11. Historique & Versions
Boot 1 (XML-less), Boot 2 (Reactive, Java 8), Boot 3 (Jakarta, Java 17+, GraalVM).
Versions GraalVM12. Outils & Écosystème
start.spring.io. Maven vs Gradle. Spring Cloud (Microservices). Liens.
Spring Boot est un "accélérateur" pour le Spring Framework (l'écosystème Java/Kotlin n°1). C'est un framework "opinioné" (opinionated) qui simplifie radicalement la création d'applications "production-ready".
Le Problème (Avant Spring Boot)
Le Spring Framework classique était incroyablement puissant, mais nécessitait des *centaines* de lignes de configuration XML (beans.xml, web.xml...) juste pour démarrer. Il fallait tout configurer à la main (le serveur, la BDD, le mapping...).
La Solution (Spring Boot)
La philosophie de Boot est "Convention over Configuration" (La Convention prime sur la Configuration), inspirée de Ruby on Rails :
- Auto-configuration : Boot "voit" les
.jardans votre projet (ex: il voitspring-boot-starter-web) et *configure automatiquement* un serveur Tomcat, Jackson (pour le JSON), etc. - Serveur Embarqué : Plus besoin de déployer des
.war. Boot *inclut* Tomcat (ou Jetty/Undertow) dans le.jarfinal. L'application se lance avec une simple commandejava -jar app.jar. - "Starters" : Des "kits" de dépendances (voir 1.3) qui simplifient la gestion (Maven/Gradle).
C'est le *cœur* du Spring Framework (que Boot utilise).
IoC (Inversion of Control) : C'est le framework qui gère le cycle de vie de vos objets (les "Beans"), et non l'inverse.
DI (Dependency Injection) : C'est *comment* l'IoC fonctionne. Au lieu qu'une classe A "crée" (new) une classe B, elle la "demande" dans son constructeur, et Spring (le "conteneur") la lui "injecte".
Mauvais (Sans DI)
// Le contrôleur est "couplé" à l'implémentation
public class MonController {
private final MonService service;
public MonController() {
// MAUVAIS: Le contrôleur crée sa propre dépendance
this.service = new MonServiceImpl();
}
// ... (difficile à tester)
}
Bon (Avec DI)
Le contrôleur demande une *interface*, pas une classe.
@RestController
public class MonController {
private final IMonService service;
// BIEN: On "demande" la dépendance (Injection Constructeur)
// Spring va la trouver et l'injecter.
@Autowired
public MonController(IMonService service) {
this.service = service;
}
// ... (Facile à tester avec un "Mock")
}
@Service
class MonServiceImpl implements IMonService {
// ...
}
Stéréotypes (Les "Beans")
Pour que Spring "trouve" vos classes, vous devez les annoter :
@Component: Le stéréotype de base ("C'est un Bean").@Service: Sémantique ("C'est une logique métier").@Repository: Sémantique ("C'est une classe d'accès aux données", ex: DAO).@Controller/@RestController: Sémantique ("C'est un point d'entrée Web").
Les "Starters" (pom.xml / build.gradle)
Un "Starter" n'est pas du code. C'est un descripteur de dépendances (Maven/Gradle). C'est un "kit" qui importe un ensemble de .jar cohérents.
| Starter | Ce qu'il inclut (Auto-configure) |
|---|---|
spring-boot-starter-web | Spring MVC, Validation, Serveur Tomcat (embarqué), Jackson (JSON). |
spring-boot-starter-data-jpa | Spring Data JPA, Hibernate (ORM), connecteurs de BDD (HikariCP). |
spring-boot-starter-security | Spring Security (filtres, protection CSRF, authentification). |
spring-boot-starter-test | JUnit 5, Mockito, AssertJ, MockMvc. |
spring-boot-starter-actuator | Endpoints de monitoring (/health, /metrics). |
L'Auto-Configuration (La "Magie")
C'est le cœur de Boot. La logique est :
1. Vous ajoutez spring-boot-starter-web à votre pom.xml.
2. Boot le voit au démarrage.
3. Il dit : "Ah, le développeur veut faire du web."
4. Il *auto-configure* (active) un Tomcat embarqué, un DispatcherServlet (le routeur), et Jackson (le convertisseur JSON).
Résultat : Vous pouvez créer un @RestController et il "juste marche", sans *une seule* ligne de XML ou de config.
L'auto-configuration est "opinionée", mais vous pouvez *surcharger* (override) chaque opinion via un fichier de configuration centralisé, situé dans src/main/resources/.
application.properties (Style Java)
# Change le port du serveur (défaut 8080) server.port=8081 # Configuration de la base de données spring.datasource.url=jdbc:postgresql://localhost:5432/mydb spring.datasource.username=admin spring.datasource.password=secret # Niveaux de logs logging.level.org.springframework.web=DEBUG
application.yml (Style YAML)
(Préféré car moins répétitif et hiérarchique)
# Change le port
server:
port: 8081
# Configuration BDD (hiérarchique)
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: admin
password: secret
logging:
level:
org.springframework.web: DEBUG
Injecter des Propriétés (@Value)
Pour lire une propriété de configuration dans une classe :
@Service
public class MonService {
// Injecte la valeur de la clé 'mon.secret.api'
@Value("${mon.secret.api}")
private String apiKey;
// ...
}
C'est le cas d'usage n°1 de Spring Boot : créer des APIs REST (JSON).
Anatomie d'un @RestController
@RestController: Indique à Spring que cette classe est un contrôleur Web, et que ses méthodes doivent renvoyer du JSON (@ResponseBody) par défaut.@RequestMapping("/api/users"): Définit l'URL de base pour ce contrôleur.@GetMapping,@PostMapping, ... : Lient une méthode à un verbe HTTP et à une sous-route.@PathVariable: Extrait une variable du chemin (/users/{id}).@RequestParam: Extrait une variable de la query string (/search?q=...).@RequestBody: Désérialise le JSON du "body" (POST/PUT) dans un objet Java (POJO).ResponseEntity: Permet un contrôle total sur la réponse (status code, headers, body).
Exemple (CRUD)
// (UserDto est un simple POJO Java)
public record UserDto(long id, String name) {}
@RestController
@RequestMapping("/api/users")
public class UserController {
// (Injecté par DI, voir 1.2)
private final UserService userService;
// GET /api/users/123
@GetMapping("/{id}")
public ResponseEntity<UserDto> getUserById(@PathVariable long id) {
UserDto user = userService.findById(id);
if (user == null) {
return ResponseEntity.notFound().build(); // Renvoie 404
}
return ResponseEntity.ok(user); // Renvoie 200 + JSON
}
// POST /api/users
@PostMapping
public ResponseEntity<UserDto> createUser(@RequestBody UserCreateDto dto) {
// (Le JSON est auto-validé si on ajoute @Valid)
UserDto newUser = userService.create(dto);
// Renvoie 201 Created + Header "Location: /api/users/124"
return ResponseEntity
.created(URI.create("/api/users/" + newUser.id()))
.body(newUser);
}
}
Avant les SPAs (React/Vue), Spring était (et est toujours) utilisé pour le rendu HTML côté serveur avec le pattern MVC (Model-View-Controller).
@Controller vs @RestController
@RestController: Dit "renvoie du JSON (ou XML)".@Controller: Dit "renvoie un *nom de template* (string) que le moteur de vue (Thymeleaf) doit interpréter".
Thymeleaf (Le "moteur de template" moderne)
Oubliez les .jsp. Le "plugin" moderne est Thymeleaf (spring-boot-starter-thymeleaf). Il permet d'écrire du HTML "naturel" avec des attributs th:.
Controller (MonController.java)
@Controller // (Pas @RestController)
public class WebController {
@GetMapping("/hello")
public String getHello(Model model) {
// 1. Ajouter des données au "Modèle"
model.addAttribute("username", "Alice");
model.addAttribute("isAdmin", true);
// 2. Renvoyer le nom du fichier HTML
// (Spring va chercher /templates/accueil.html)
return "accueil";
}
}
View (/templates/accueil.html)
(Nécessite spring-boot-starter-thymeleaf)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<!-- 1. Afficher la variable (interpolation) -->
<h1 th:text="|Bonjour, ${username}!|">Bonjour, Guest!</h1>
<!-- 2. Condition (th:if) -->
<div th:if="${isAdmin}">
<p>Vous êtes admin.</p>
</div>
</body>
</html>
Spring Data JPA n'est pas un ORM. C'est une *couche d'abstraction* (un "plugin") au-dessus d'un ORM (généralement Hibernate). JPA (Java Persistence API) est le standard, Hibernate est l'implémentation, et Spring Data JPA rend tout cela "magique".
1. L'Entité (@Entity)
C'est le Modèle (POJO) mappé à une table de BDD. (javax.persistence.* ou jakarta.persistence.* pour Boot 3+).
@Entity // (Dit à JPA: "Ceci est une table")
@Table(name = "utilisateurs")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
// (Getters & Setters omis pour la clarté)
}
2. Le Repository (L'interface "magique")
C'est la *vraie* puissance. Vous n'écrivez *pas* l'implémentation (le DAO). Vous écrivez juste une interface qui hérite de JpaRepository.
// 1. Vous écrivez CECI :
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 2. "Derived Query" : Spring Data écrit le SQL pour vous !
// (SELECT * FROM users WHERE username = ?)
Optional<User> findByUsername(String username);
// (SELECT * FROM users WHERE age > ? ORDER BY username)
List<User> findByAgeGreaterThanOrderByUsername(int age);
// 3. (Optionnel) Requête custom (JPQL)
@Query("SELECT u FROM User u WHERE u.email LIKE '%@gmail.com'")
List<User> findAllGmailUsers();
}
// 3. Dans votre Service, vous injectez et utilisez :
@Service
public class MonService {
@Autowired
private UserRepository userRepo;
public void demo() {
userRepo.save(new User(...));
List<User> users = userRepo.findByAgeGreaterThan(18);
}
}
Spring Security est le "plugin" officiel (via spring-boot-starter-security) pour gérer l'authentification (AuthN) et l'autorisation (AuthZ).
Attention : L'implémentation a *radicalement* changé depuis Spring Boot 2.7. L'ancien WebSecurityConfigurerAdapter est obsolète. La nouvelle méthode (Boot 3+) utilise des @Bean.
Exemple : Configuration Moderne (SecurityFilterChain)
Ceci définit le "pipeline" des filtres de sécurité. (Ex: pour une API REST JWT).
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // (Pour @PreAuthorize)
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 1. Désactiver CSRF (non-pertinent pour les APIs REST stateless)
.csrf(csrf -> csrf.disable())
// 2. Gérer la session (Stateless pour JWT)
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 3. Définir les règles d'autorisation
.authorizeHttpRequests(authz -> authz
// Permet l'accès à /api/auth/** (login/register)
.requestMatchers("/api/auth/**").permitAll()
// Exige l'authentification pour tout le reste
.anyRequest().authenticated()
);
// (Ici, on ajouterait le filtre de validation JWT :
// .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
return http.build();
}
}
Autorisation au niveau méthode (@PreAuthorize)
@RestController
@RequestMapping("/api/admin")
public class AdminController {
// Seuls les utilisateurs avec le RÔLE 'ADMIN' peuvent appeler ceci.
// (Nécessite @EnableMethodSecurity)
@GetMapping
@PreAuthorize("hasRole('ADMIN')")
public String getAdminData() {
return "Données Admin secrètes";
}
}
Le spring-boot-starter-test est un "plugin" qui importe JUnit 5 (framework de test), Mockito (framework de mocking), et AssertJ (assertions fluides).
@SpringBootTest (Test d'Intégration)
Charge le contexte Spring *complet* (tous les Beans, la BDD...). C'est lourd, mais teste l'intégration de bout en bout.
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MonAppIntegrationTest {
@Autowired
private TestRestTemplate restTemplate; // Un client HTTP de test
@Test
void testRootEndpoint() {
String body = this.restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World!");
}
}
@WebMvcTest (Test "Slice")
Ne charge *que* la couche Web (le Controller). C'est beaucoup plus rapide. Les services (@Service) sont "mockés" (simulés).
@WebMvcTest(UserController.class) // Ne teste QUE ce contrôleur
class UserControllerTest {
@Autowired
private MockMvc mockMvc; // Simule les appels HTTP (pas de vrai serveur)
// Simule (Mock) le service, car il n'est pas chargé
@MockBean
private UserService userService;
@Test
void testGetUser() throws Exception {
// 1. Setup du Mock
UserDto user = new UserDto(1L, "Alice");
given(userService.findById(1L)).willReturn(user);
// 2. Exécution & Assertions
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Alice"));
}
}
Actuator (spring-boot-starter-actuator) est le "plugin" officiel pour le monitoring. Il expose des endpoints HTTP "internes" (/actuator/...) pour que les outils (Kubernetes, Prometheus) puissent vérifier l'état de l'application.
Endpoints Incontournables
| Endpoint | Description |
|---|---|
/actuator/health | Le plus important. Vérifie l'état de santé (liveness/readiness). (Renvoie {"status": "UP"}). |
/actuator/info | Affiche des infos custom (ex: version git, build time). |
/actuator/metrics | Affiche des métriques (usage CPU, mémoire JVM, ...). |
/actuator/prometheus | Expose les métriques au format Prometheus (standard de monitoring). |
/actuator/env | Affiche les variables d'environnement (Sensible !). |
Configuration (application.yml)
Par défaut (sécurité), seul /health est exposé. On doit exposer les autres manuellement :
# application.yml
management:
endpoints:
web:
# Expose 'health', 'info', et 'prometheus'
exposure:
include: "health,info,prometheus"
# exclude: "env" (Exclure les sensibles)
# Configuration détaillée de l'endpoint 'health'
endpoint:
health:
# Affiche les détails (ex: BDD connectée ? Disque OK ?)
show-details: always
# (Activer les "readiness" et "liveness" probes pour Kubernetes)
probes:
enabled: true
Spring Boot a une cadence de sortie rapide (une version majeure tous les ~2 ans), alignée sur les versions de Java.
| Version | Date Sortie | Version Java (Base) | Nouveautés Clés |
|---|---|---|---|
| Spring Boot 1.0 | Avr 2014 | Java 6 | La Révolution : "Convention over Config", Auto-configuration, Starters, Serveur embarqué. |
| Spring Boot 2.0 | Mar 2018 | Java 8 | Le "Reactive Stack" : Support de Spring WebFlux (async/non-blocking) en parallèle de Spring MVC (bloquant). Java 8 requis. |
| Spring Boot 2.7 | Mai 2022 | Java 8 | Mise à jour majeure de Spring Security (abandon de WebSecurityConfigurerAdapter). |
| Spring Boot 3.0 | Nov 2022 | Java 17 | Le "Grand Saut" : - Java 17+ requis. - Migration de javax.* à jakarta.* (Jakarta EE 9+). - Support natif de GraalVM (compilation AOT - Ahead-of-Time). |
| Spring Boot 3.2 | Nov 2023 | Java 17 | Support des "Virtual Threads" (Java 21). |
| Spring Boot 3.3 | Mai 2024 | Java 17 | Améliorations GraalVM, support "baseline" de Java 22. |
L'écosystème Spring (géré par VMWare/Broadcom) est le plus vaste de l'univers Java.
Outils (Build & Démarrage)
| Outil | Description |
|---|---|
start.spring.io | Le point de départ N°1. Un générateur web ("initializer") qui crée votre pom.xml (Maven) ou build.gradle. Vous cochez les "Starters" (Web, JPA, Security) dont vous avez besoin. |
Maven (pom.xml) | Le gestionnaire de dépendances/build "classique" (XML). |
Gradle (build.gradle) | Le gestionnaire de dépendances/build "moderne" (Groovy/Kotlin). Plus rapide et plus flexible que Maven. |
Frameworks "Frères" (Plugins)
- Spring Cloud : Un "framework de frameworks" pour les microservices. (Service Discovery (Eureka), Config Server, Gateway (API Gateway), Circuit Breaker (Resilience4j)).
- Spring Batch : Pour les traitements "batch" lourds (ex: import de masse, jobs de nuit).
- Spring Integration : Pour l'intégration EAI (connexion à des systèmes via FTP, AMQP, ...).
