프레임워크/Spring

[Spring] RestTemplate와 webClient

멍토 2021. 8. 23.

프로젝트를 진행하면서 외부 API를 요청해야 하는 일이 생겼다.

그래서 외부 API를 요청하는 방법을 찾게되었고 외부에 API를 요청하는 방법이 여러가지가 있었다.

  1. Java에서 지원하는 HttpURLConnection
  2. Spring에서 지원하는 RestTemplate
  3. Spring에서 지원하는 WebClient

Java에서 지원하는 기능은 자원을 우리가 다 관리해야 하며 복잡하기 때문에 Spring에서 지원하는 기능을 사용하기로 했다.

RestTemplate

Spring 3.0부터 나왔다.

블록킹 동기로 동작한다.

그렇지만 스프링 5.0으로 들어오고나서 WebClient가 나오고 유지보수만 진행되고 있다.

As of 5.0 the RestTemplate is in maintenance mode, with only minor requests for changes and bugs to be accepted going forward. Please, consider using the WebClient which offers a more modern API and supports sync, async, and streaming scenarios.

앞으로 지원하지 않는다는 글을 보고 WebClient를 사용하기로 했다.

WebClient

Spring 5.0부터 나왔다.

Spring MVC 기반이 아닌 Spring WebFlux 기반이다.

기존의 블록킹/동기였던 RestTemplate과 다르게 논블록킹/비동기를 지원한다.

따라서 추가적인 작업을 해야할때 요청후 작업을 함으로써 속도를 단출할 수 있다.

RestTemplate보다 적은수의 쓰레드와, 리소스를 이용하여 더 많은 로직을 처리할 수 있다.

Mono와 Flux를 사용한다.

Mono : 0 ~ 1 개의 결과를 처리하기위한 Reactor 객체이다.

Flux : 0 ~ N 개의 결과를 처리하기 위한 Reactor 객체이다.

추가내용

(공식문서에서 찾아볼 필요가 있다. 블로그 참조)

HTTP 호출 결과를 가져오기 위한 방법이 2가지가 있다.

retrieve()와 exchange() 이다.

exchange를 사용하게 되면 세세한 컨트롤이 가능하나 memory leak의 가능성이 생기기 때문에 retrieve를 사용하도록 권고되고 있다.

WebClinet는 Reactive Stream기반이기 때문에 리턴값이 Mono 혹은 Flux이다.

Spring WebFlux를 이용하고 있다면 문제가 없지만 Spring MVC기반이라면 반환값을 객체로 변환해야하는 과정이 생긴다.

이럴때 데이터를 받아오기 위해서 .block()을 사용하는 경우가 있다.

그렇게 된다면 main스레드에서 처리하기 때문에 사용을 자제하는게 좋다고 한다.

사용한다면 테스트때 사용하라고 한다.

대신 완벽한 Reactive 호출은 아니지만 Lazy Subscribe를 통한 Strem 또는 Iterble로 변환시킬 수 있는 Flux.toStream, Flux.toIterable() 함수를 제공하고 있다.

List<SomeData> results =
    webClient.mutate()
             .baseUrl("https://some.com/api")
             .build()
             .get()
             .uri("/resource")
             .accept(MediaType.APPLICATION_JSON)
             .retrieve()
             .bodyToFlux(SomeData.class)
             .toStream()
             .collect(Collectors.toList());
SomeData data = 
    webClient.mutate()
             .baseUrl("https://some.com/api")
             .build()
             .get()
             .uri("/resource/{ID}", id)
             .accept(MediaType.APPLICATION_JSON)
             .retrieve()
             .bodyToMono(SomeData.class)
             .flux()
             .toStream()
             .findFirst()
             .orElse(defaultValue);

출처 : https://www.baeldung.com/spring-webclient-resttemplate

https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#webmvc-resttemplate

https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-client

https://medium.com/@odysseymoon/spring-webclient-%EC%82%AC%EC%9A%A9%EB%B2%95-5f92d295edc0

댓글

💲 광고입니다.