Programowania reaktywnego ciąg dalszy! Tym razem przedstawię Ci następcę RestTemplate, czyli WebClient. Jeśli jeszcze nie wiesz co to programowanie reaktywne i jak można go wdrożyć w projekcie, to zobacz koniecznie moje wpisy na ten temat:
Wiedza przedstawiona w poprzednich artykułach jest niezbędna do pełnego zrozumienia tego, jak działa WebClient oraz przykład zaprezentowany w tym poście.
WebClient vs. RestTemplate
RestTemplate jest to klient HTTP dostarczany przez Spring Web. Umożliwia on blokującą komunikację, czyli wątek przetwarzający jest blokowany aż do momentu odebrania i przetworzenia wiadomości. W skrócie jest to przykład komunikacji synchronicznej.
WebClient jest to nowy asynchroniczny klient HTTP, który umożliwia konsumowanie zasobów opakowanych w strumienie Flux i Mono. Jednocześnie udostępnia też konsumowanie standardowych REST API, które nie są zaimplementowane z użyciem programowania reaktywnego. WebClient jest niejako następcą RestTemplate i został wprowadzony w Spring WebFlux.
Przykład zastosowania WebClient
Jako przykład stworzymy prostą aplikację w Spring Boot, która będzie udostępniała listę obiektów typu Person. Aby pokazać Ci asynchroniczną naturę WebClient, poszczególne elementy listy będą zwracane z pewnym opóźnieniem 🙂
W pliku pom.xml musimy dodać odpowiednią zależność do WebFlux:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
W kolejnym kroku dodamy klasę Person, o której wspomniałem już wcześniej. Będzie to zwykła klasa typu POJO, która ma za zadanie przetrzymywać informacje zwracane przez asynchroniczny endpoint. Do szybszej implementacji tej klasy użyłem projektu Lombok, o którym możesz dowiedzieć się więcej tutaj.
package com.ara.webclient.demo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class Person {
private String firstName;
private String lastName;
private int age;
}
Na koniec dodamy kontroler, który udostępni nam jeden endpoint typu GET.
package com.ara.webclient.demo;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.time.Duration;
@RestController
public class ReactiveRestApiController {
@GetMapping(produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<Person> getSomething() {
return getData();
}
@EventListener(ApplicationReadyEvent.class)
private Flux<Person> getData() {
return Flux.just(
new Person("First Name 1", "Last Name 1", 31),
new Person("First Name 2", "Last Name 2", 32),
new Person("First Name 3", "Last Name 3", 33),
new Person("First Name 4", "Last Name 4", 34),
new Person("First Name 5", "Last Name 5", 35),
new Person("First Name 6", "Last Name 6", 36),
new Person("First Name 7", "Last Name 7", 37),
new Person("First Name 8", "Last Name 8", 38)
).delayElements(Duration.ofSeconds(1));
}
}
Warto zauważyć, że typ zwracany przez endpoint to wspomniany wcześniej typ Flux. Kolejną interesującą rzeczą jest dodanie sekundowego opóźnienia, z jakim będą zwracane kolejne elementy strumienia asynchronicznego (linia 32). Pozwoli to na zaprezentowanie, że nasz endpoint faktycznie działa asynchronicznie.
Aby to zaprezentować, nagrałem krótki film, na którym widać dokładnie, że poszczególne elementy strumienia przychodzą z sekundowym opóźnieniem.
Podsumowanie
Asynchroniczne REST API może przydać się w miejscach, gdzie musimy przetwarzać duże ilości danych, co zajmuję czas. Oczywiście można też użyć WebClient jedynie jako zamiennik RestTemplate i zwracać dane synchronicznie.
Jeśli podobał Ci się ten artykuł, to proszę, zostaw komentarz, like na Facebook lub w innym miejscu!
Oczywiście cały kod aplikacji, która posłużyła nam za przykład znajduję się na moim Github’ie: