Spring WebFlux – Programowanie reaktywne

spring-webflux-programowanie-reaktywne
Czas czytania: 3 minut

Co to jest Spring WebFlux?

Spring WebFlux jest to reaktywny moduł Spring’a, pozwalający na zastosowanie reaktywnych strumieni oraz użycie nieblokujących się kontenerów aplikacji takich jak Netty lub Undertown. Oczywiście możemy też skonfigurować Tomcat’a jako kontener nieblokujący, lecz wcześniej wymienione serwery aplikacji zostały zaprojektowane od podstaw tak, aby można było je wykorzystywać do rozwiązań typu non-blocking.

Spring WebFlux jest to implementacja paradygmatu programowania reaktywnego w Spring Framework 5. Jeśli nie wiesz, czym jest ten paradygmat, to zanim przejdziesz dalej, zachęcam Cię do przeczytania artykułu na temat programowania reaktywnego, w którym dowiesz się więcej na jego temat.

https://arasoftware.pl/2020/07/01/programowanie-reaktywne

Ok, skoro już wiesz, czym jest paradygmat programowania reaktywnego, to przejdźmy do jego implementacji w Spring’u. Cały moduł Spring WebFlux został oparty o Project Reaktor. Jest to biblioteka stworzona do programowania reaktywnego w języku Java.


Dodanie Spring WebFlux do projektu

Maven
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webflux -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
    <version>2.3.1.RELEASE</version>
</dependency>

Gradle
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webflux
compile group: 'org.springframework.boot', name: 'spring-boot-starter-webflux', version: '2.3.1.RELEASE'


Strumień Flux

Jest to reaktywny strumień (Publisher), który może wyemitować od 0 do N elementów. Implementuje on interfejs Publisher<T> i może posiadać jedną z trzech wartości:

  • element – obiekt
  • sygnał sukcesu
  • sygnał błędu

Poniżej znajduję się schemat działania strumienia Flux:

Schemat działania strumienia Flux.
Przykład użycia strumienia Flux

Utwórzmy klasę Person, która będzie posiadać informacje o imieniu oraz wieku osoby.

public class Person() {
   public int age;
   public String name;
   // constructor
   // getters and setetrs
}

W kolejnym kroku dodajmy kontroler, który będzie udostępniał endpoint „getRandomPersons” typu GET. Będzie on zwracał listę obiektów typu Person z losowymi danymi.

@RestController
public class WebFluxConstructor {

    @GetMapping("/persons")
    private Flux<Person> getAllPersons() {
        return Flux.just(new Person(new Random().nextInt(), UUID.randomUUID().toString()),
                new Person(new Random().nextInt(), UUID.randomUUID().toString()),
                new Person(new Random().nextInt(), UUID.randomUUID().toString()));
    }
}

Po uruchomieniu aplikacji widzimy, że nie została ona uruchomiona na serwerze Tomcat, jak to się dzieje standardowo dla Spring Boot, lecz na Netty. Oczywiście wszystko za sprawą WebFliux’a, który to potrzebuje do działania serwera non-blocking.

2020-07-06 15:05:46.234  INFO 30956 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080

Po wywołaniu adresu ” http://localhost:8080/persons” w przeglądarce otrzymamy wynik zbliżony do poniższego. Nie jest to typowy response w postaci JSON, lecz strumień danych.

[{"age":-770853828,"name":"3326acf9-1d20-4712-a760-ddefbb1de81e"},{"age":22283567,"name":"22791c71-2d9d-4d29-b37c-841e2b13b7cf"},{"age":1324763993,"name":"12639158-9ecd-4df8-a83e-45d35ce1bec4"}]


Strumień Mono

Strumień Mono jest bardzo podobny do Flux z tą różnicą, że przyjmuje on 0 lub jeden element. Można powiedzieć, że jest to uproszczona wersja Flux. Taki podział na dwa różne strumienie daje programiście możliwość jasnego zdefiniowania czy dana funkcjonalność ma udostępniać jeden lub wiele elementów danego typu.

Schemat działania strumienia Mono został przedstawiony na poniższym obrazku:

Schemat działania strumienia Mono.

Implementacja endpointu, który wykorzystuję strumień Mono do udostępniania danych, jest bardzo podobna jak ta w przypadku Flux.

Tym razem dodamy dwa parametry, które będą odpowiadać za imię i wiek osoby, której dane chcemy pobrać.

    @GetMapping("/person/{name}/{age}")
    private Mono<Person> getEmployeeByNameAndAge(@PathVariable String name, @PathVariable int age) {
        return Mono.just(new Person(age, name));
    }

Jako response zapytania ” http://localhost:8080/person/Radek/30 ” otrzymamy obiekt Person:

{"age":30,"name":"Radek"}

Podsumowanie

Oczywiście jest to prosta implantacja, która nie wykorzystuje połączenia z bazą danych. Jednak zawsze można zastąpić ciało metod w kontrolerze i udostępniać dane zapisane w bazie. Pamiętajże połączenie do bazy danych także powinno być nieblokujące.

Podobał Ci się ten artykuł? Udostępnij go i podziel się nim ze swoimi znajomymi!

Czy ten post był dla Ciebie pomocny?

Kliknij na gwiazdki żeby zagłosować.

Średnia ocena 4.9 / 5. Liczba głosów: 7

Brak głosów do tej pory. Bądź pierwszy(a)!

Bardzo mi przykro że ten post nie był dla Ciebie pomocny 🙁

Pozwól mi poprawić ten post!

Powiedz mi co mogę poprawić?