Spring WebClient vs. RestTemplate

REST Top

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs

1. Einleitung

In diesem Tutorial werden zwei Web-Client-Implementierungen von Spring verglichen - RestTemplate und der reaktive alternative WebClient von Spring 5 .

2. Blocking vs. Non-Blocking Client

In Webanwendungen ist es häufig erforderlich, HTTP-Aufrufe an andere Dienste zu tätigen. Daher benötigen wir ein Web-Client-Tool.

2.1. RestTemplate Blocking Client

Spring bietet RestTemplate seit langem als Webclient-Abstraktion an. Unter der Haube verwendet RestTemplate die Java-Servlet-API, die auf dem Thread-per-Request-Modell basiert .

Dies bedeutet, dass der Thread blockiert wird, bis der Webclient die Antwort erhält. Das Problem mit dem Blockierungscode ist darauf zurückzuführen, dass jeder Thread etwas Speicher- und CPU-Zyklen verbraucht.

Betrachten wir viele eingehende Anfragen, die auf einen langsamen Service warten, der zur Erzielung des Ergebnisses erforderlich ist.

Früher oder später häufen sich die Anfragen, die auf die Ergebnisse warten. Folglich erstellt die Anwendung viele Threads, die den Thread-Pool erschöpfen oder den gesamten verfügbaren Speicher belegen . Aufgrund des häufigen Wechsels des CPU-Kontexts (Thread) kann es auch zu Leistungseinbußen kommen.

2.2. Nicht blockierender WebClient -Client

Auf der anderen Seite verwendet WebClient eine asynchrone, nicht blockierende Lösung, die vom Spring Reactive-Framework bereitgestellt wird .

Während RestTemplate den Aufrufer-Thread für jedes Ereignis verwendet (HTTP-Aufruf), erstellt WebClient für jedes Ereignis so etwas wie eine „Aufgabe“. Hinter den Kulissen stellt das Reactive Framework diese „Aufgaben“ in die Warteschlange und führt sie nur aus, wenn die entsprechende Antwort verfügbar ist.

Das Reactive Framework verwendet eine ereignisgesteuerte Architektur. Es bietet Mittel zum Erstellen asynchroner Logik über die Reactive Streams-API. Infolgedessen kann der reaktive Ansatz im Vergleich zur Synchron- / Blockierungsmethode mehr Logik verarbeiten, während weniger Threads und Systemressourcen verwendet werden.

WebClient ist Teil der Spring WebFlux-Bibliothek. Daher können wir zusätzlich Client-Code unter Verwendung einer funktionalen, fließenden API mit reaktiven Typen ( Mono und Flux ) als deklarative Zusammensetzung schreiben .

3. Vergleichsbeispiel

Um die Unterschiede zwischen diesen beiden Ansätzen zu demonstrieren, müssten Leistungstests mit vielen gleichzeitigen Clientanforderungen durchgeführt werden. Nach einer bestimmten Anzahl paralleler Clientanforderungen würde sich bei der Blockierungsmethode eine erhebliche Leistungsverschlechterung ergeben.

Andererseits sollte die reaktive / nicht blockierende Methode unabhängig von der Anzahl der Anforderungen konstante Leistungen liefern.

In diesem Artikel implementieren wir zwei REST-Endpunkte, einen mit RestTemplate und einen mit WebClient . Ihre Aufgabe ist es, einen anderen langsamen REST-Webdienst aufzurufen, der eine Liste von Tweets zurückgibt.

Für den Anfang benötigen wir die Spring Boot WebFlux-Starterabhängigkeit:

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

Außerdem ist hier unser REST-Endpunkt für langsamen Service:

@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. Verwenden von RestTemplate zum Aufrufen eines langsamen Dienstes

Implementieren wir nun einen weiteren REST-Endpunkt, der unseren langsamen Service über den Webclient aufruft.

Zunächst verwenden wir 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; }
     
    

When we call this endpoint, due to the synchronous nature of RestTemplate, the code will block waiting for the response from our slow service. Only when the response has been received, the rest of the code in this method will be executed. In the logs, we'll see:

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. Using WebClient to Call a Slow Service

Secondly, let's use WebClient to call the slow service:

@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 this case, WebClient returns a Flux publisher and the method execution gets completed. Once the result is available, the publisher will start emitting tweets to its subscribers. Note that a client (in this case, a web browser) calling this /tweets-non-blocking endpoint will also be subscribed to the returned Flux object.

Let's observe the log this time:

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])

Note that this endpoint method completed before the response was received.

4. Conclusion

In this article, we explored two different ways of using web clients in Spring.

RestTemplate verwendet die Java-Servlet-API und ist daher synchron und blockierend. Im Gegensatz dazu ist WebClient asynchron und blockiert den ausführenden Thread nicht, während auf die Antwort gewartet wird. Erst wenn die Antwort fertig ist, wird die Benachrichtigung erstellt.

RestTemplate wird weiterhin verwendet. In einigen Fällen verbraucht der nicht blockierende Ansatz viel weniger Systemressourcen als der blockierende. In diesen Fällen ist WebClient daher die bevorzugte Wahl.

Alle im Artikel erwähnten Codefragmente finden Sie auf GitHub.

REST unten

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs