Pour rappel, dans le document Introduction au framework Spring, Erik Gollot avançait que Spring est effectivement un conteneur dit « léger », c’est-à-dire une infrastructure similaire à un serveur d'applications Java EE. Il prend donc en charge la création d’objets et la mise en relation d’objets par l’intermédiaire d’un fichier de configuration qui décrit les objets à fabriquer et les relations de dépendances entre ces objets. Le gros avantage par rapport aux serveurs d’application est qu’avec Spring, les classes n’ont pas besoin d’implémenter une quelconque interface pour être prises en charge par le framework (au contraire des serveur d'applications Java EE et des EJBs). C’est en ce sens que Spring est qualifié de conteneur « léger ».
Cette version apporte un nouveau framework web fonctionnel qui est basé sur la programmation réactive qui a été apportée dans Spring 5.0 M1. C’est Arjen Poutsma, un ingénieur qui fait également partie du projet, qui s’est chargé de présenter quelques extraits des bénéfices de ce framework avec l’échantillon d’application qui est disponible sur GitHub. Ci-dessous, un dépôt réactif qui expose des objets Person. Il ressemble en de nombreux points à un dépôt traditionnel non réactif, en dehors du fait qu’il retourne Flux<Person> où vous aurez retourné List<Person> et Mono<Person> où vous aurez retourné Person. Ici Mono<Void> est utilisé en guise de complétion du signal afin de signaler lorsque la sauvegarde est terminée.
Code : | Sélectionner tout |
1 2 3 4 5 | public interface PersonRepository { Mono<Person> getPerson(int id); Flux<Person> allPeople(); Mono<Void> savePerson(Mono<Person> person); } |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | RouterFunction<?> route = route(GET("/person/{id}"), request -> { Mono<Person> person = Mono.justOrEmpty(request.pathVariable("id")) .map(Integer::valueOf) .then(repository::getPerson); return Response.ok().body(fromPublisher(person, Person.class)); }) .and(route(GET("/person"), request -> { Flux<Person> people = repository.allPeople(); return Response.ok().body(fromPublisher(people, Person.class)); })) .and(route(POST("/person"), request -> { Mono<Person> person = request.body(toMono(Person.class)); return Response.ok().build(repository.savePerson(person)); })); |
Code : | Sélectionner tout |
1 2 3 4 5 | HttpHandler httpHandler = RouterFunctions.toHttpHandler(route); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); HttpServer server = HttpServer.create("localhost", 8080); server.startAndAwait(adapter); |
HandlerFunction : le point de départ de ce nouveau framework est HandlerFunction<T>, qui est essentiellement une Function<Request, Response<T>>, où Request et Response sont des interfaces nouvellement définies et non permutables qui offrent un DSL JDK-8 friendly aux messages HTTP sous-jacents. Voici un exemple simple d’une HandlerFunction qui retourne une réponse avec un statut 200.
Code : | Sélectionner tout |
1 2 | HandlerFunction<String> helloWorld = request -> Response.ok().body(fromObject("Hello World")); |
Code : | Sélectionner tout |
1 2 3 4 5 | RouterFunction<?> route = route(path("/hello-world"), request -> Response.ok().body(fromObject("Hello World"))) .and(route(path("/the-answer"), request -> Response.ok().body(fromObject("42")))); |
FilterFunction : les chemins mappés par une fonction d’acheminement peuvent être filtrés en faisant appel à RouterFunction.filter(FilterFunction<T, R>, où FilterFunction<T,R> est essentiellement une BiFunction<Request, HandlerFunction<T>, Response<R>>. La fonction Handler en paramètre représente le prochain élément de la chaîne. Notons qu’une autre FilterFunction peut être appliquée à sa place si de multiples filtres sont requis.
Et comment exécuter ces fonctions sur un serveur HTTP ? En appelant une autre fonction : HttpHandler. Il est possible de convertir une fonction d’acheminement en HttpHandler en se servant de RouterFunctions.toHttpHandler().
En gros, dans ce nouveau framework web proposé par Spring, ce que nous pouvons retenir c’est que :
- les fonctions de gestion (Handler) s’occupent des requêtes en retournant des réponses ;
- les fonctions d’acheminement font parvenir les requêtes entrantes aux fonctions de gestion et peuvent être composées de plusieurs fonctions d’acheminement ;
- les fonctions d’acheminement peuvent être filtrées par des fonctions de filtrage ;
- les fonctions d’acheminement peuvent être exécutées dans un environnement d’exécution web réactif.
exemple illustratif de projet utilisant ce nouveau framework (GitHub)
Source : blog Spring
Voir aussi :
Quels modules de Spring utilisez-vous en 2016 ? Venez partager votre expérience