Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Java Spring
  3. Stack web reactive Spring
Extrait - Java Spring Construisez vos applications réactives avec une architecture micro-services en environnement Jakarta EE (2e édition)
Extraits du livre
Java Spring Construisez vos applications réactives avec une architecture micro-services en environnement Jakarta EE (2e édition) Revenir à la page d'achat du livre

Stack web reactive Spring

Introduction à la stack web réactive

La stack web réactive de Spring est un élément de Spring Framework destiné à développer des applications web modernes et réactives. Elle comprend principalement Spring WebFlux pour créer des services web réactifs et WebClient pour interagir de manière réactive avec des services HTTP externes. Cette technologie garantit d’excellentes performances, une efficacité en ressources et une adaptabilité, en particulier pour les microservices ou les applications nécessitant une grande réactivité. Elle supporte également les WebSockets pour une communication bidirectionnelle continue et RSocket pour des environnements à faible latence. Cela permet aux développeurs de concevoir des applications web réactives, robustes et adaptées aux contextes en temps réel et hautement concurrents.

Spring WebFlux est un module de Spring Framework conçu pour le développement d’applications web réactives et asynchrones, offrant haute performance et extensibilité. Il se distingue par sa programmation basée sur des flux réactifs, la flexibilité de son modèle de threading, le support des WebSockets et RSocket pour une communication en temps réel, et une approche réactive intégrale. WebFlux est compatible avec plusieurs...

Noyau réactif

Le module Spring Web propose un support fondamental pour les applications web réactives avec deux niveaux de support pour le traitement des requêtes côté serveur. D’une part, HttpHandler, qui gère les requêtes HTTP avec une I/O non bloquante. D’autre part, l’API WebHandler, polyvalente pour la gestion des requêtes, sur laquelle reposent les contrôleurs annotés et les points d’extrémité (endpoints) fonctionnels. Pour le côté client, le module fournit un contrat de base ClientHttpConnector pour les requêtes HTTP avec une I/O non bloquante et Reactive Streams, ainsi que des adaptateurs pour divers serveurs tels que Reactor Netty, le client réactif Jetty et Apache HttpComponents.

Le WebClient, utilisé dans les applications, est construit sur ce contrat de base. En outre, le module propose des codecs pour la sérialisation et la désérialisation du contenu des requêtes et réponses HTTP, tant pour le client que pour le serveur. Cela permet de gérer efficacement le flux de données et de faciliter le développement d’applications web réactives.

HttpHandler

1. Généralités

Le module Spring Web propose le HttpHandler, une interface de base pour gérer les requêtes HTTP dans les applications web réactives. Il permet de traiter les requêtes entrantes et de fournir des réponses appropriées tout en utilisant une I/O non bloquante et en prenant en charge la backpressure de Reactive Streams. Le HttpHandler est compatible avec divers serveurs web réactifs tels que Reactor Netty, Undertow, Tomcat, Jetty ou d’autres conteneurs Servlet en fonction de l’adaptateur utilisé. Il offre une abstraction de bas niveau pour la gestion des requêtes et peut être utilisé pour construire des modèles de programmation plus élevés, comme les contrôleurs annotés ou les points d’extrémité fonctionnels. En utilisant le HttpHandler, les applications peuvent traiter les requêtes sans bloquer le thread, améliorant ainsi l’efficacité d’utilisation des ressources système. Cela permet aux applications d’être hautement performantes, évolutives et de gérer efficacement de nombreuses requêtes simultanées sans surcharger le système. Le choix du serveur web dépend du contexte, et la version Reactor Netty est souvent préférée pour ses performances. Nous nous concentrons principalement sur Reactor Netty. Cependant, d’autres serveurs sont également envisageables, en particulier dans des environnements spécifiques...

API WebHandler

Le package org.springframework.web.server offre une API web polyvalente basée sur le contrat HttpHandler, permettant de traiter les requêtes via une chaîne composée de WebExceptionHandler, WebFilter et un seul WebHandler. L’assemblage de cette chaîne se fait facilement avec WebHttpHandlerBuilder, en détectant automatiquement les composants via ApplicationContext ou en les enregistrant manuellement.

L’API WebHandler étend HttpHandler en fournissant des fonctionnalités supplémentaires pour les applications web, comme la gestion des sessions utilisateur, les attributs de requête, les données de formulaire, etc. Elle simplifie le développement tout en restant puissante. Cette API supérieure permet de construire des modèles de programmation spécifiques tels que les contrôleurs annotés ou les points d’extrémité fonctionnels. Le WebHandler est une interface fonctionnelle qui gère les requêtes (ServerRequest) et renvoie les réponses asynchrones (Mono<ServerResponse>). Il utilise les métadonnées de la requête pour prendre des décisions et renvoyer une réponse personnalisée au client.

Voici un exemple simple d’un WebHandler qui renvoie une réponse avec le statut 200 OK et un corps contenant "Hello, World!" en tant que texte brut :

public...

WebHttpHandlerBuilder

Le tableau ci-dessous répertorie les composants que WebHttpHandlerBuilder peut détecter automatiquement dans un objet ApplicationContext, ou qui peuvent être enregistrés directement avec lui.

  • WebExceptionHandler : 0 à N instances pour gérer les exceptions provenant de la chaîne de WebFilter et du WebHandler cible.

  • WebFilter : 0 à N instances pour appliquer une logique d’interception avant et après le reste de la chaîne de filtres et le WebHandler cible.

  • WebHandler : 1 instance pour gérer la requête.

  • WebSessionManager : 0 à 1 instance pour gérer les sessions web exposées via une méthode sur ServerWebExchange. Utilise DefaultWebSessionManager par défaut.

  • ServerCodecConfigurer : 0 à 1 instance pour accéder aux instances HttpMessageReader pour parser les données de formulaire et les données multipart exposées ensuite via des méthodes sur ServerWebExchange. Utilise ServerCodecConfigurer.create() par défaut.

  • LocaleContextResolver : 0 à 1 instance pour résoudre le LocaleContext exposé via une méthode sur ServerWebExchange. Utilise AcceptHeaderLocaleContextResolver par défaut.

  • ForwardedHeaderTransformer : 0 à 1 instance pour traiter les en-têtes de type "forwarded", soit en les extrayant...

ServerWebExchange

ServerWebExchange est une interface centrale de Spring WebFlux qui représente l’échange d’informations entre le client et le serveur lors du traitement d’une requête HTTP. Il encapsule toutes les informations pertinentes sur la requête entrante et fournit des méthodes pour accéder à ces informations et pour modifier la réponse renvoyée au client. Nous verrons comment l’utiliser à travers de nombreux exemples.

Spring WebFlux

Spring WebFlux est le pendant réactif de Spring MVC.

1. Aspects principaux pour démarrer

WebFlux est principalement conçu pour créer des serveurs REST dynamiques. Même s’il est efficace dans ce domaine, il n’est pas recommandé pour servir des pages telles que JSP, JSF, Thymeleaf, etc., car nous obtenons de meilleurs résultats avec les SPA (Single Page Applications). Pour le côté client, nous privilégions l’utilisation de WebClient, qui est l’alternative à RestTemplate dans Spring MVC. Dans cette démarche, nous nous focaliserons initialement sur la mise en place des serveurs REST, les clients WebClient et l’intégration de la sécurité via Spring Security. En coulisses, Spring WebFlux tire parti de Reactor Core, y compris ses implémentations Flux et Mono.

Spring WebFlux propose deux modèles de programmation :

  • le routage et la manipulation fonctionnelle

  • les composants réactifs fondés sur des annotations

Par la suite nous montrerons comment utiliser les divers composants à travers des exemples qui utiliseront ces deux modèles de programmation et nous traiterons ensuite des particularités de chacun.

a. Sécurité minimale

Il faut configurer un minimum la sécurité via une classe de configuration :

@Configuration  
@EnableWebFluxSecurity  
public class ExempleSecurityConfig {  
  
  @Bean  
  public MapReactiveUserDetailsService userDetailsService() {  
    UserDetails user = User.withDefaultPasswordEncoder()  
      .username("user")  
      .password("user")  
      .roles("USER")  
      .build();  
    return new MapReactiveUserDetailsService(user);  
  }  
} 

Cette configuration intègre une authentification par formulaire ainsi qu’une authentification HTTP basique. Elle exige qu’un utilisateur soit authentifié pour accéder aux pages. Par ailleurs, une page de connexion et une page de déconnexion par défaut sont mises en place. Des en-têtes HTTP spécifiques...

WebSocket(s) réactive(s)

Le protocole WebSocket, RFC 6455, offre un moyen standardisé d’établir une communication bidirectionnelle en full-duplex entre le client et le serveur via une seule connexion TCP. Bien que ce soit un protocole TCP différent de HTTP, il est conçu pour fonctionner sur HTTP, utilisant les ports 80 et 443, ce qui permet de réutiliser les règles de pare-feu existantes.

Une interaction WebSocket commence par une requête HTTP qui utilise l’en-tête HTTP Upgrade pour passer au protocole WebSocket.

Après une poignée de main réussie, la socket TCP sous-jacente reste ouverte, permettant au client et au serveur de continuer à envoyer et recevoir des messages. 

Il est à noter que si un serveur WebSocket fonctionne derrière un serveur web (comme nginx), il est probablement nécessaire de le configurer pour transférer les requêtes d’upgrade de WebSocket vers le serveur WebSocket. De même, si l’application est hébergée dans un environnement cloud, il faut vérifier les instructions du fournisseur concernant le support de WebSocket. Même si WebSocket est conçu pour être compatible avec HTTP, il est crucial de comprendre que ces deux protocoles conduisent à des architectures et des modèles de programmation très différents. En général, avec HTTP, une application est modélisée avec plusieurs URL accessibles via des requêtes. En revanche, avec WebSocket, il y a généralement une seule URL pour la connexion initiale, puis tous les messages de l’application passent par cette même connexion, ce qui suggère une architecture entièrement différente. WebSocket peut rendre une page web dynamique et interactive. Cependant, une combinaison d’AJAX et de streaming HTTP ou d’interrogation longue (long polling) peut souvent suffire. Par exemple, pour des actualités ou des e-mails, une mise à jour toutes les quelques minutes peut être suffisante. Mais pour des jeux ou des applications financières, le temps réel est essentiel. Il est également important de noter que sur Internet, certains proxys restrictifs peuvent empêcher les interactions WebSocket. Cela signifie que l’utilisation de WebSocket pour des applications...

WebClient

Le WebClient est la partie miroir du côté serveur Spring WebFlux. Il est également voué à être utilisé avec Spring MVC, car le RestTemplate risque de disparaître au profit du WebClient. Le WebClient est une classe de Spring WebFlux qui permet d’effectuer des requêtes HTTP de manière réactive. Il offre une interface fluide pour effectuer des appels RESTful et récupérer les réponses de manière asynchrone.

Nous avons déjà croisé quelques utilisations du WebClient dans nos exemples précédents.

Voici un exemple d’utilisation de WebClient pour effectuer une requête GET vers une API REST :

public class WebClientExample {  
  
  public static void main(String[] args) {  
    // Création d'un client WebClient  
    WebClient webClient = WebClient.create("https://api.example.com"); 
  
    // Exemple de requête GET vers une API REST  
    Mono<String> responseMono = webClient.get()  
      .uri("/endpoint")  
      .retrieve()  
      .bodyToMono(String.class);  
  
    // Abonnement à la réponse et traitement de la donnée  
    responseMono.subscribe(  
      response -> System.out.println("Réponse : " + response),  
      error -> System.err.println("Erreur : " + error.getMessage()) 
    );  
  
    // Attendre la fin de l'exécution pour que la requête ait le temps 
    // de se terminer  
    try {  
      Thread.sleep(3000);  
    } catch (InterruptedException e) {  
      e.printStackTrace();  
    }  
  }  
} 

Dans cet exemple, nous avons créé un objet WebClient avec WebClient.create(), puis nous avons effectué une requête...

RSocket

RSocket est un protocole innovant conçu pour la communication entre applications, permettant des échanges bidirectionnels via différents modes de transport comme TCP et WebSocket. C’est un protocole d’application offrant une sémantique de flux réactifs. Il fonctionne, par exemple, comme une alternative à HTTP.

Il propose quatre principaux modèles d’interaction :

  • Demande-Réponse : un message est envoyé, et une réponse est attendue.

  • Demande-Flux : un message est envoyé, donnant lieu à un flux de réponses.

  • Canal : échanges continuels et bidirectionnels de messages.

  • Envoyer-et-Oublier : envoi d’un message sans attente de retour.

Une fois la connexion établie, il n’y a pas de distinction stricte entre client et serveur, les deux peuvent initier n’importe quelle interaction. Cela donne une symétrie, avec les termes « demandeur » et « répondeur » utilisés pour les décrire. Ces interactions peuvent être désignées comme des « flux de demandes » ou simplement « demandes ».

Les avantages de RSocket sont nombreux, y compris la gestion des flux réactifs, la régulation des demandes, la capacité de reprendre des sessions après des interruptions, et plus encore. Il s’appuie sur des technologies comme Reactor pour ses implémentations Java.

La connexion débute par un client se connectant à un serveur à travers un transport et envoie une trame de configuration appelée SETUP. Une fois cette trame acceptée, les échanges peuvent commencer librement entre les deux parties. Chaque demande émise est marquée par une trame spécifique, et le répondeur renvoie des trames PAYLOAD en réponse.

Les messages RSocket sont composés de données et de métadonnées, qui peuvent avoir des fonctions diverses, telles que la spécification d’une route ou la transmission d’un jeton de sécurité. Les métadonnées sont généralement spécifiques à une demande, envoyées dans le premier message de cette demande. Certaines extensions de protocole définissent...

Conclusion

En conclusion, l’utilisation de la stack web réactive de Spring avec WebFlux, WebSocket et RSocket offre de nombreux avantages pour le développement d’applications modernes et performantes. La programmation réactive permet de gérer efficacement un grand nombre de connexions simultanées avec une utilisation optimale des ressources matérielles, ce qui en fait une solution idéale pour les applications web haute performance.

Avec Spring WebFlux, nous pouvons développer des applications réactives qui répondent aux exigences de scalabilité et de réactivité des environnements modernes. Les flux réactifs (Mono et Flux) permettent de gérer les opérations asynchrones de manière élégante et concise, offrant ainsi une meilleure expérience utilisateur.

L’intégration des WebSockets dans la stack réactive de Spring permet de créer des applications en temps réel, facilitant la communication bidirectionnelle entre le serveur et le client. Cela permet d’implémenter des fonctionnalités en temps réel, telles que les notifications, le chat en direct, les tableaux de bord dynamiques, etc.

Quant à RSocket, il apporte une communication réactive entre les microservices avec des caractéristiques uniques telles que la gestion de la demande et de la réponse...