Spring WebClient e RestTemplate

REST Top

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO

1. Introduzione

In questo tutorial, confronteremo due delle implementazioni del client Web di Spring: RestTemplate e il nuovo WebClient alternativo reattivo di Spring 5 .

2. Client bloccante e non bloccante

È un requisito comune nelle applicazioni Web effettuare chiamate HTTP ad altri servizi. Pertanto, abbiamo bisogno di uno strumento client web.

2.1. RestTemplate Blocking Client

Per molto tempo, Spring ha offerto RestTemplate come astrazione del client Web. Dietro le quinte, RestTemplate utilizza l'API Java Servlet, che si basa sul modello thread per richiesta .

Ciò significa che il thread si bloccherà fino a quando il client Web non riceverà la risposta. Il problema con il codice di blocco è dovuto al fatto che ogni thread consuma una certa quantità di memoria e cicli della CPU.

Consideriamo la presenza di molte richieste in arrivo, in attesa di un servizio lento necessario per produrre il risultato.

Prima o poi le richieste in attesa dei risultati si accumuleranno. Di conseguenza, l'applicazione creerà molti thread, che esauriranno il pool di thread o occuperanno tutta la memoria disponibile . È inoltre possibile che si verifichi una riduzione delle prestazioni a causa del frequente cambio di contesto (thread) della CPU.

2.2. Client non bloccante WebClient

Dall'altro lato, WebClient utilizza una soluzione asincrona e non bloccante fornita dal framework Spring Reactive .

Mentre RestTemplate utilizza il thread del chiamante per ogni evento (chiamata HTTP), WebClient creerà qualcosa come un "compito" per ogni evento. Dietro le quinte, il framework Reactive metterà in coda quelle "attività" e le eseguirà solo quando sarà disponibile la risposta appropriata.

Il framework Reactive utilizza un'architettura guidata dagli eventi. Fornisce i mezzi per comporre la logica asincrona tramite l'API Reactive Streams. Di conseguenza, l'approccio reattivo può elaborare più logica utilizzando meno thread e risorse di sistema, rispetto al metodo sincrono / di blocco.

WebClient fa parte della libreria Spring WebFlux. Pertanto, possiamo inoltre scrivere codice client utilizzando un'API funzionale e fluida con tipi reattivi ( Mono e Flux ) come composizione dichiarativa .

3. Esempio di confronto

Per dimostrare le differenze tra questi due approcci, avremmo bisogno di eseguire test delle prestazioni con molte richieste client simultanee. Vedremmo una riduzione significativa delle prestazioni con il metodo di blocco dopo un certo numero di richieste client parallele.

D'altra parte, il metodo reattivo / non bloccante dovrebbe dare prestazioni costanti, indipendentemente dal numero di richieste.

Ai fini di questo articolo, implementiamo due endpoint REST, uno utilizzando RestTemplate e l'altro utilizzando WebClient . Il loro compito è chiamare un altro servizio web REST lento, che restituisce un elenco di tweet.

Per cominciare, avremo bisogno della dipendenza di avvio Spring Boot WebFlux:

 org.springframework.boot spring-boot-starter-webflux 

Inoltre, ecco il nostro endpoint REST del servizio lento:

@GetMapping("/slow-service-tweets") private List getAllTweets() { Thread.sleep(2000L); // delay return Arrays.asList( new Tweet("RestTemplate rules", "@user1"), new Tweet("WebClient is better", "@user2"), new Tweet("OK, both are useful", "@user1")); }

3.1. Utilizzo di RestTemplate per chiamare un servizio lento

Implementiamo ora un altro endpoint REST che chiamerà il nostro servizio lento tramite il client web.

In primo luogo, useremo RestTemplate :

@GetMapping("/tweets-blocking") public List getTweetsBlocking() { log.info("Starting BLOCKING Controller!"); final String uri = getSlowServiceUri(); RestTemplate restTemplate = new RestTemplate(); ResponseEntity
    
      response = restTemplate.exchange( uri, HttpMethod.GET, null, new ParameterizedTypeReference
     
      (){}); List result = response.getBody(); result.forEach(tweet -> log.info(tweet.toString())); log.info("Exiting BLOCKING Controller!"); return result; }
     
    

Quando chiamiamo questo endpoint, a causa della natura sincrona di RestTemplate , il codice si bloccherà in attesa della risposta dal nostro servizio lento. Solo quando la risposta è stata ricevuta, il resto del codice in questo metodo verrà eseguito. Nei log vedremo:

Starting BLOCKING Controller! Tweet(text=RestTemplate rules, [email protected]) Tweet(text=WebClient is better, [email protected]) Tweet(text=OK, both are useful, [email protected]) Exiting BLOCKING Controller!

3.2. Utilizzo di WebClient per chiamare un servizio lento

In secondo luogo, usiamo WebClient per chiamare il servizio lento:

@GetMapping(value = "/tweets-non-blocking", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux getTweetsNonBlocking() { log.info("Starting NON-BLOCKING Controller!"); Flux tweetFlux = WebClient.create() .get() .uri(getSlowServiceUri()) .retrieve() .bodyToFlux(Tweet.class); tweetFlux.subscribe(tweet -> log.info(tweet.toString())); log.info("Exiting NON-BLOCKING Controller!"); return tweetFlux; }

In questo caso, WebClient restituisce un editore Flux e l'esecuzione del metodo viene completata. Una volta che il risultato è disponibile, l'editore inizierà a inviare tweet ai suoi abbonati. Notare che un client (in questo caso, un browser web) che chiama questo endpoint / tweets-non-blocking verrà sottoscritto anche all'oggetto Flux restituito .

Questa volta osserviamo il registro:

Starting NON-BLOCKING Controller! Exiting NON-BLOCKING Controller! Tweet(text=RestTemplate rules, [email protected]) Tweet(text=WebClient is better, [email protected]) Tweet(text=OK, both are useful, [email protected])

Notare che questo metodo endpoint è stato completato prima della ricezione della risposta.

4. Conclusione

In questo articolo, abbiamo esplorato due diversi modi di utilizzare i client Web in primavera.

RestTemplate utilizza Java Servlet API ed è quindi sincrono e bloccante. Al contrario, WebClient è asincrono e non bloccherà il thread in esecuzione in attesa del ritorno della risposta. Solo quando la risposta è pronta verrà prodotta la notifica.

RestTemplate verrà comunque utilizzato. In alcuni casi, l'approccio non bloccante utilizza molte meno risorse di sistema rispetto a quello bloccante. Quindi, in quei casi, WebClient è una scelta preferibile.

Tutti gli snippet di codice, menzionati nell'articolo, possono essere trovati su GitHub.

REST fondo

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO