Créer une Simple application REST Réactive avec Spring 5/WebFlux et Reactor

yagni.tech code & craft team
5 min readDec 17, 2018

--

Durant ce tutoriel nous allons essayer de créer une application Rest réactive avec le nouveau module spring webFlux

Spring Web Flux est un module de spring qui fournit le support de la programmation réactive pour les applications web, ce module coexiste avec spring web-mvc dans Spring framework (Oui ils sont des voisins 😮).

Une application lamda peut utiliser les deux modules, le diagramme suivant montre comment les deux sont liés, ce qu’ils ont en commun et ce que chacun supporte de manière unique

D’abord, commençons par définir le mot à la mode “Réactif” 🎓

Ce que vous connaissez sûrement c’est que java utilise des pools de threads pour l’exécution simultanée d’opérations liées aux E/S ( un appel webservice par exemple) le grand inconvénient c’est qu’il est difficile de faire évoluer l’application puisque à chaque fois il faut un thread supplémentaire , pour remédier à cela, il existe une proposition java qui est le projet Loom qui présente un modèle de thread léger, mais nous savons toujours pas quand est-ce que ce projet sera en production 😐
Alors comment nous pouvons rendre nos applications non bloquantes 😲 ??
Api asynchrone, oui nous pouvons utiliser CompletableFuture introduit dans Java 8, qui nous a fourni une API fluide du type asynchrone.

CompletableFuture.supplyAsync(() -> {
return ProductService.getProduct(productId);
}).thenAccept(product -> {
System.out.println(" product name : " + product.getName())
});

C’est mieux 😉, mais il accepte qu’une seule valeur ,donc il faut chercher une solution pour prendre en charge une séquence en asynchrone; Java a déjà fourni l’Api Stream qui est conçu uniquement pour les collections et qui propose un ensemble d’opérations fonctionnelles, nous distinguons deux types:

  • Les opérations finales : elles produisent un résultat ou un « side-effect »
  • Les opérations intermédiaires : elles transforment un Stream en autre Stream

En effet, après l’introduction de la programmation fonctionnelle dans Java 8, il est devenu possible pour des frameworks comme Spring de développer un module qui répond au besoin cité en dessus.

Spring-webflux a été crée pour pouvoir gérer des appels HTTP non bloquantes, avec un petit nombre de thread et faire évoluer l’application avec un minimum de ressources matérielles.
Il se base sur la bibliothèque Reactor écrite en Java et développée en collaboration avec Spring, le projet Reactor fournit les classes Mono<T> et Flux<T> qui permettent de travailler sur une séquence de données (0–1) pour Mono et (1-N) pour Flux et utilise un vocabulaire riche d’opérateurs de la bibliothèque ReactiveX.

Ce qu’il faut retenir, c’est que Reactor est une bibliothèque de flux réactive , par conséquent tous les opérateurs proposés par ses classes sont non bloquants.

Le module Spring webFlux est pris en charge par les conteneurs Tomcat, Jetty, Servlet 3.1+ ainsi que les environnements d’exécution tels que Undertow et netty.
Spring Boot 2 propose un démarreur web réactif, par défaut il utilise netty mais vous pouvez le modifier facilement via les dépendances maven ou gradle

Il faut bien noter que l’adoption d’un code réactif ne permettra pas aux applications de s’exécuter plus rapidement, mais comme nous l’avons cité en dessus le principal avantage des applications non bloquantes (réactives) est la possibilité de s’adapter à un nombre de thread restreint et une mémoire réduite.

Maintenant nous avons un minimum de théorie pour pouvoir passer à la pratique 👌

Let’s code

Prérequis:

  • Une bonne base du langage Java
  • Une bonne connaissance sur le framework Spring
  • Des notions sur Spring boot

Outils

  • JDK 8 minmum
  • Votre IDE préféré ( Idea, STS, Eclipse …)
  • Maven 3.2 minimum

Initialisation de l’application

Nous allons utiliser le démarreur spring boot pour webflux , pour simplifier et accélérer les choses vous pouvez passer par https://start.spring.io/

Les dépendances Maven

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

Côté Maven, nous avons besoin du démarreur boot pour webflux, de la dépendance Spring boot et de la bibliothèque Reactor sur laquelle il se base webflux pour gérer les flux réactifs.

Handler

Dans l’approche du Spring réactive, nous utilisons des Handlers pour gérer des requests et créer des responses

Nous allons créer un ProductHandler qui va envoyer une liste de produits comme suite :

package fr.tuto.app.reactive.rest.handler;

import fr.tuto.app.reactive.rest.model.Product;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

@Component
public class ProductHandler {

private List<Product> products = Arrays.asList(
new Product(1, "Lit", "ADB123"),
new Product(2, "Canapé", "ADPO23"),
new Product(3, "Chaise", "OPMLE23")
);

public Mono<ServerResponse> getProduct(ServerRequest serverRequest) {
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).
body(BodyInserters.fromObject(products));
}

}

C’est une classe simple qui retournera tout le temps une liste de produits en format JSON.

Router

Ensuite, il faut créer une route pour notre service.
Créerons la classe ProductRouter

package fr.tuto.app.reactive.rest.router;

import fr.tuto.app.reactive.rest.handler.ProductHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.*;

@Configuration
public class ProductRouter {

@Bean
public RouterFunction<ServerResponse> route(ProductHandler productHandler){
return RouterFunctions.route(RequestPredicates.GET("/products")
.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), productHandler::getProduct);
}
}

Notre routeur écoute sur le port 8081 et attend la réception d’une requête sur le chemin /products et renvoie la liste des produits.

WebCLient

Maintenant nous allons créer un WebClient, nous ne pourrions pas passer par RestTemplate car il gère seulement les appels bloquants, cependant il faut passer par la classe WebClient du module Reactive.

package fr.tuto.app.reactive.rest.client;

import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

public class ProductWebClient {

private WebClient webClient = WebClient.create("http://localhost:8081");

private Mono<ClientResponse> result = webClient.get()
.uri("/products")
.accept(MediaType.APPLICATION_JSON)
.exchange();

public String getResult() {
return ">> result = " +
result.flatMap(res -> res.bodyToMono(String.class)).block();
}

}

Pour créer un webClient , nous utilisons la méthode create, nous pouvons passer également par le builder proposé par la classe WebClient.builder() .
Notre webClient utilise la classe Mono qui permet de récupérer d’une manière réactive le contenu de l’uri “/products”

Il reste qu’a exécuter notre application Spring boot 😮

package fr.tuto.app.reactive.rest;

import fr.tuto.app.reactive.rest.client.ProductWebClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RestApplication {

public static void main(String[] args) {

SpringApplication.run(RestApplication.class, args);
ProductWebClient gwc = new ProductWebClient();
System.out.println(gwc.getResult());
}
}

Vous devez obtenir le résultat suivant :

résultat spring boot

Nous allons voir dans un prochain article comment créer une application web avec webFlux en passant par les contrôleurs annotés 😃

Le code est disponible sous GitHub

--

--

yagni.tech code & craft team
yagni.tech code & craft team

Written by yagni.tech code & craft team

Digital Factory , we Build & Run Amazing Apps

Responses (3)