Spring WebClient срещу RestTemplate

ПОЧИВКА Най-горе

Току що обявих новия курс Learn Spring , фокусиран върху основите на Spring 5 и Spring Boot 2:

>> ПРЕГЛЕД НА КУРСА

1. Въведение

В този урок ще сравним две реализации на уеб клиента на Spring - RestTemplate и реактивния алтернативен WebClient на Spring 5 .

2. Блокиране срещу неблокиращ клиент

Често изискване в уеб приложенията е да извършвате HTTP разговори към други услуги. Следователно се нуждаем от инструмент за уеб клиент.

2.1. Клиент за блокиране на RestTemplate

От дълго време Spring предлага RestTemplate като абстракция на уеб клиент. Под капака RestTemplate използва API на Java Servlet, който се основава на модела на нишка на заявка .

Това означава, че нишката ще се блокира, докато уеб клиентът получи отговора. Проблемът с блокиращия код се дължи на това, че всяка нишка консумира известно количество памет и цикли на процесора.

Нека помислим за много входящи заявки, които чакат някаква бавна услуга, необходима за получаване на резултата.

Рано или късно заявките, чакащи резултатите, ще се натрупват. Следователно приложението ще създаде много нишки, които ще изчерпят пула от нишки или ще заемат цялата налична памет . Също така можем да изпитаме влошаване на производителността поради честото превключване на контекста на процесора (нишката).

2.2. Неблокиращ клиент на WebClient

От друга страна, WebClient използва асинхронно, неблокиращо решение, предоставено от Spring Reactive рамката .

Докато RestTemplate използва нишката на повикващия за всяко събитие (HTTP повикване), WebClient ще създаде нещо като „задача“ за всяко събитие. Зад кулисите, реактивната рамка ще постави на опашка тези „задачи“ и ще ги изпълни само когато е налице подходящият отговор.

Реактивната рамка използва управлявана от събития архитектура. Той предоставя средства за съставяне на асинхронна логика чрез API за реактивни потоци. В резултат на това реактивният подход може да обработва повече логика, като използва по-малко нишки и системни ресурси в сравнение с метода на синхронно / блокиране.

WebClient е част от пролетната библиотека WebFlux. Следователно можем допълнително да напишем клиентски код, като използваме функционален, плавен API с реактивни типове ( Mono и Flux ) като декларативен състав .

3. Пример за сравнение

За да демонстрираме разликите между тези два подхода, ще трябва да изпълним тестове за производителност с много едновременни клиентски заявки. Ще видим значително влошаване на производителността с метода за блокиране след определен брой паралелни клиентски заявки.

От друга страна, реактивният / неблокиращ метод трябва да дава постоянни характеристики, независимо от броя на заявките.

За целите на тази статия, нека внедрим две крайни точки REST, едната използва RestTemplate, а другата използва WebClient . Тяхната задача е да извикат друга бавна уеб услуга REST, която връща списък с туитове.

За начало ще ни трябва Spring Boot WebFlux стартерна зависимост:

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

Освен това, тук е нашата крайна точка за бавно обслужване REST:

@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. Използване на RestTemplate за извикване на бавна услуга

Нека сега внедрим друга крайна точка REST, която ще извика нашата бавна услуга чрез уеб клиента.

Първо, ще използваме 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; }
     
    

Когато извикаме тази крайна точка, поради синхронния характер на RestTemplate , кодът ще блокира изчакването на отговора от нашата бавна услуга. Само когато отговорът е получен, останалата част от кода в този метод ще бъде изпълнена. В дневниците ще видим:

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. Използване на WebClient за извикване на бавна услуга

Второ, нека използваме WebClient, за да извикаме бавната услуга:

@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; }

В този случай WebClient връща издател на Flux и изпълнението на метода завършва. След като резултатът е наличен, издателят ще започне да издава туитове на своите абонати. Имайте предвид, че клиент (в този случай уеб браузър), извикващ тази / tweets-non-blocking endpoint, също ще бъде абониран за върнатия обект Flux .

Нека да наблюдаваме дневника този път:

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

Обърнете внимание, че този метод на крайна точка е завършен преди получаването на отговора.

4. Заключение

В тази статия разгледахме два различни начина за използване на уеб клиенти през пролетта.

RestTemplate използва Java Servlet API и следователно е синхронен и блокиращ. Обратно, WebClient е асинхронен и няма да блокира изпълняващата нишка, докато чака връщането на отговора. Само когато отговорът е готов, известието ще бъде представено.

RestTemplate ще продължи да се използва. В някои случаи неблокиращият подход използва много по-малко системни ресурси в сравнение с блокиращия. Следователно в тези случаи WebClient е предпочитан избор.

Всички кодови фрагменти, споменати в статията, могат да бъдат намерени в GitHub.

ПОЧИВКА отдолу

Току що обявих новия курс Learn Spring , фокусиран върху основите на Spring 5 и Spring Boot 2:

>> ПРЕГЛЕД НА КУРСА