Dernière modification : 04/01/2026

Évolution de Spring Boot 3 à Spring Boot 4 (release finale)

Les nouveautés majeures

 

Spring Boot 4 (sorti en novembre 2025) ouvre une nouvelle “génération” Spring en s’appuyant sur Spring Framework 7. L’idée globale : moderniser le socle (Jakarta EE 11, Jackson 3…), rendre l’écosystème plus sûr (null-safety), plus modulaire (dépendances mieux ciblées), et améliorer la DX côté REST, résilience et tests.

 

Avant de parler des nouvelles fonctionnalités, plusieurs pré-requis techniques évoluent :

  • Java :
    • Java 17 est requis.
    • Java 21 et 25 sont fortement recommandées pour profiter des nouveautés de la JVM, notamment les threads virtuels.
  • Spring Framework 7 & Jakarta EE 11. L’adoption complète de Jakarta EE 11 implique :
    • Servlet 6.1
    • JPA 3.2
    • Bean Validation 3.1
  • Kotlin :
    • Support de Kotlin 2.2+, avec une meilleure intégration des coroutines et une expérience plus fluide pour le code réactif.

 

I. Les nouveautés liées à Spring Boot 4

I.1. Améliorations Native Image

Spring Boot 4 renforce le support des images natives GraalVM (v24).  Le framework est désormais aligné avec GraalVM 24, ce qui apporte plus de stabilité et de cohérence dans les builds natifs.
Le traitement AOT (Ahead-of-Time : compilation anticipée) est optimisé. Ce qui signifie un temps de build réduits, un démarrage plus rapide et une empreinte mémoire plus faible.

Spring Data introduit les AOT Repositories. Le traitement AOT transforme les méthodes de requête en code source qui sont compilées avec l'application. Pour plus d'information : Documentation Spring.

 

I.2. Observabilité : Micrometer 2 et OpenTelemetry

L’observabilité continue d’évoluer. Après l’introduction de Spring Observability dans la version précédente, Spring Boot 4 adopte Micrometer 2 et fournit l'intégration du starter d’OpenTelemetry. Cette approche facilite la corrélation entre métriques, logs et traces.

Le starter spring-boot-starter-opentelemetry est le “nouveau” point d’entrée Boot 4 pour pousser en OTLP.

Configuration Maven (pom.xml) :

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <!-- Traces/metrics/logs via OTLP (Boot 4) -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-opentelemetry</artifactId>
  </dependency>

  <!-- Health/metrics endpoints + probes K8s -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
  </dependency>

  <!-- Optionnel - Pour /actuator/prometheus -->
  <dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
  </dependency>
</dependencies>

Fichier de configuration (application.yml) :

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus

Exemple d'endpoint : http://localhost:8080/actuator

 

I.3. Amélioration du reporting SSL

Les certificats SSL proches de l’expiration sont désormais listés dans l’entrée expiringChains.
Le statut WILL_EXPIRE_SOON disparaît et ces certificats restent marqués comme VALID.

Cela simplifie la supervision en production en réduisant les faux positifs, tout en conservant une visibilité claire sur les expirations à venir.

 

 

II. Les nouveautés liées à Spring Framework 7

II.1 Améliorations côté tests via RestTestClient

Spring Framework 7 fait évoluer l’exécution des tests, en s’appuyant toujours sur le mécanisme de Context Caching, utilisé pour trouver un compromis entre performances et isolation des tests. Ce mécanisme reste essentiel, mais il présentait jusqu’ici certaines limites, notamment dans les suites d’intégration de grande taille.

Désormais, une nouvelle capacité de mise en pause des contextes de test est introduite. Auparavant, les contextes associés à des tests d’intégration de longue durée continuaient à consommer des ressources même lorsqu’ils n’étaient plus actifs. Désormais, Spring peut suspendre puis réactiver les contextes stockés dans le cache, ce qui permet de réduire la consommation mémoire et d’accélérer l’exécution globale des suites de tests. Cette amélioration est particulièrement utile pour les scénarios impliquant des composants persistants, comme des listeners JMS ou des tâches planifiées.

En parallèle, Spring introduit un nouveau RestTestClient, pensé pour simplifier les tests d’API REST. Il offre une expérience proche de WebTestClient, avec une syntaxe lisible et expressive, tout en évitant l’introduction de dépendances réactives. Les tests REST gagnent en simplicité, sans imposer WebFlux ou une dépendance réactive.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class GreetingEndpointIT {

    private RestTestClient restClient;

    @BeforeEach
    void initClient(WebApplicationContext applicationContext) {
        this.restClient = RestTestClient
            .bindToApplicationContext(applicationContext)
            .build();
    }

    @Test
    void shouldReturnGreetingMessageV1() {
        restClient.get()
            .uri("/api/v1/greeting")
            .exchange()
            .expectStatus().isOk()
            .expectHeader().contentTypeCompatibleWith(MediaType.TEXT_PLAIN)
            .expectBody(String.class)
            .consumeWith(response ->
                assertThat(response.getResponseBody())
                    .containsIgnoringCase("greeting")
            );
    }
}

 

II.2 Versionnage d’API simplifié

Gérer proprement plusieurs versions d’une API REST était jusque-là laissé à la charge du développeur (URI différentes, headers custom, etc.). Spring Boot 4 introduit un support first-class du versioning d’API au niveau du mapping des contrôleurs. Il permet d’annoter les contrôleurs REST avec une version d’API cible, via la propriété version sur les @RequestMapping (et autres annotations dérivées).

@RestController
@RequestMapping("/search")
class ProductController {
    @GetMapping(version = "1")
    List<ProductV1> searchV1(@RequestParam String query) { ... }

    @GetMapping(version = "2")
    ProductSearchResponseV2 searchV2(@RequestParam String query,
                                        @RequestParam(defaultValue="10") int limit) { ... }
}

Ou au niveau du controller

@RestController
@RequestMapping("/search", version = "3")
class ProductController {
    @GetMapping()
    ProductSearchResponse search(@RequestParam String query,
                                        @RequestParam(defaultValue="10") int limit) { ... }
}

Spring propose plusieurs mécanismes standards pour déterminer la version d’une API entrante :

  • Versionnement par le chemin (path-based) - Exemple : /api/v1/search et /api/v2/search

  • Versionnement par paramètre de requête - Exemple : /search?version=1 et /search?version=2

  • Versionnement par en-tête HTTP - Exemple : X-API-Version: 1 et X-API-Version: 2

  • Versionnement par media type (header Accept) - Exemple : Accept: application/json;version=1 et Accept: application/json;version=2

Dans l’exemple ci-dessous, la configuration repose sur un versionnement par le chemin, où la version est directement intégrée à l’URL.

@Configuration
public class RestApiVersioningConfig implements WebMvcConfigurer {

    @Override
    public void configureApiVersioning(ApiVersionConfigurer apiVersioning) {
        apiVersioning.usePathSegment(1);
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer pathMatch) {
        // Automatically prefix all REST controllers with the API version
        pathMatch.addPathPrefix(
            "/api/v{version}",
            HandlerTypePredicate.forAnnotation(RestController.class)
        );
    }
}

 

II.3 Simplification de la configuration des clients HTTP grâce à @ImportHttpServices

Une autre évolution marquante concerne le support des clients HTTP déclaratifs. Inspirée de Feign, cette approche est toutefois plus légère et surtout nativement intégrée à Spring.

Dans les versions précédentes, il fallait créer manuellement un proxy à partir d’une HttpExchange. Des solutions plus élégantes existaient, mais elles étaient généralement faites maison.

Désormais, Spring propose une solution intégrée avec l’annotation @ImportHttpServices. Elle permet de déclarer simplement un client HTTP sous forme d’interface, que Spring se charge ensuite de transformer automatiquement en bean prêt à l’emploi.

public interface GreetingApiClient {
    @GetExchange("/messages/random")
    String fetchRandomMessage();
}

Activation du scan et configuration du groupe HTTP.

@Configuration
@ImportHttpServices(group = "GreetingApiClient", types = {GreetingApiClient.class})
public class ClientConfig {

}

Injection et utilisation côté contrôleur

@RestController
@RequestMapping(path = "/api/greeting", produces = MediaType.TEXT_PLAIN_VALUE)
@RequiredArgsConstructor
public class GreetingController {

    private final GreetingApiClient greetingApiClient;

    @GetMapping
    public String greeting() {
        return greetingApiClient.fetchRandomMessage();
    }
}

Pour plus d'information : HTTP Service Client Enhancements.

 

II.4 Résilience : Retries et limitations de concurrence

Inspiré par des bibliothèques comme Spring Retry, Spring Boot 4 intègre directement dans le cœur du framework des patrons de résilience pour rendre les services plus robustes face aux défaillances. Deux nouvelles annotations font leur apparition : @Retryable et @ConcurrencyLimit.

  • Retry automatique : En annotant une méthode avec @Retryable, Spring tentera de ré-exécuter l’opération en cas d’échec, selon une politique configurable (nombre de tentatives, délai et facteur d’exponentiation entre les tentatives, exceptions à prendre en compte, etc.). Si une méthode annotée @Retryable lance une exception, Spring la relance jusqu’à X fois avec un délai de Y seconde(s) entre chaque essai (paramètres ajustables via les attributs de l’annotation).
  • Limitation de concurrence : L’annotation @ConcurrencyLimit(n) permet de borner le nombre d’appels simultanés d’une méthode donnée. Ce mécanisme de “bulkhead” protège une ressource ou un service tiers en évitant de le solliciter au-delà d’un certain seuil de concurrence. Par exemple, @ConcurrencyLimit(10) sur une méthode critique garantit que pas plus de 10 threads à la fois ne l’exécuteront en parallèle – les appels excédentaires seront mis en attente tant que le quota n’est pas libéré.

Pour activer ces fonctionnalités, il est nécessaire d’annoter une classe de configuration avec @EnableResilientMethods.

@RestController
@RequestMapping(path = "/api/greeting", produces = MediaType.TEXT_PLAIN_VALUE)
@RequiredArgsConstructor
public class GreetingController {

    private final GreetingApiClient greetingApiClient;

    @GetMapping
    @Retryable(maxRetries = 3, delay = 10000, multiplier = 2, maxDelay = 10000)
    @ConcurrencyLimit(3)
    public String greeting() {
        return greetingApiClient.fetchRandomMessage();
    }
}

 

II.5. Null Safety avec JSpecify

Spring Boot 4 et Spring Framework 7 ont entrepris de rendre explicite la gestion des valeurs nulles à travers tout le framework. Pour cela, le projet adopte les annotations JSpecify : par exemple @NonNull et @Nullable sont ajoutées dans les signatures de méthodes et de classes du framework. L’objectif est que le compilateur (et les outils d’analyse statique) puisse détecter dès l’écriture du code les cas potentiels de null non gérés. Cela représente un grand nettoyage interne : de nombreuses APIs Spring indiquent clairement si elles peuvent retourner null ou accepter des paramètres null, ce qui aide les développeurs à éviter des bogues en traitant ces cas.

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.stereotype.Service;

@Service
class UserService {
    public @NonNull String getUserName(@Nullable String userId) {
        if (userId == null) {
            return "Inconnu";
        }
        return "Alice";
    }
}

 

 

III. Guide de migration

Vous trouverez ici un guide de migration complet : Spring Boot 4 - Migration guide.

 

 

IV. Conclusion

Spring Boot 4 inaugure une nouvelle génération du framework, plus moderne, plus robuste et mieux alignée avec les standards actuels de la JVM et du cloud. Entre le renforcement du support GraalVM, l’observabilité unifiée, la résilience intégrée et les améliorations majeures côté tests et APIs REST, cette version simplifie le développement tout en renforçant la qualité en production. La migration demande un effort mesuré, mais elle offre en retour un socle plus sûr, plus performant et durable pour les applications Spring.

Aujourd’hui, seules les versions encore officiellement supportées doivent être privilégiées en production. Elles bénéficient de correctifs de sécurité, de mises à jour régulières et d’un écosystème actif, garantissant stabilité, performances et pérennité des applications. Choisir une technologie supportée, c’est réduire les risques techniques et faciliter l’évolution future des systèmes. Vous trouverez ici la roadmap des versions encore supportées : Support.

 

 

Sources

L'écriture de cet article s'appuie sur les articles suivants :

  • https://spring.io/blog/2025/11/13/spring-framework-7-0-general-availability
  • https://spring.io/blog/2025/09/23/http-service-client-enhancements
  • https://codewiz.info/blog/spring-framework-7-and-boot-4-features/
  • https://medium.com/@vinodjagwani/spring-boot-4-0-declarative-resilience-how-to-use-retryable-and-concurrencylimit-efcd2ee8ef81
  • https://www.margo.com/blog/software-engineering/spring-boot-4-tout-comprendre-des-nouveautes-a-la-migration-complete/
  • https://www.baeldung.com/spring-boot-4-spring-framework-7

 

À noter que cet article, pour des besoins de test, a été en partie rédigé par une IA et presque entièrement reformulé, complété et vérifié par un humain.