[Spring] RestTemplate과 WebClient 이해하기
Intro
외부 API 정보를 요청하려면 어떻게 해야할까? 가장 흔하게 사용하는 방식은 Http Client 이다. Web으로 API를 호출하기 위해 사용하는 Http 모듈 중 하나인 Spring WebClient에 대해 알아보려 한다.
RestTemplate vs WebClient
기존에 많이 사용한 RestTemplate과 가장 큰 차이점은 RestTemplate는 Blocking이고, WebClient는 Non-Blocking 방식이라는 것이다. (Blocking은 호출되는 함수가 호출하는 함수에게 제어권을 넘기지 않고 대기하게 한다. Non-Blocking은 제어권을 바로 넘긴다. 관련 포스팅은 여기를 참고)
현재 RestTemplate는 Spring 5.0 이후부터 Deprecated되었고, WebClient는 앞서 설명하였듯 블로킹되지 않아 성능이 더 좋기 때문에 WebClient를 사용하기로 하였다.
또, 관련 실험 포스팅을 읽었는데 WebClient를 사용한 결과 약 5-6초 정도 단축된 것을 볼 수 있다. (유익한 포스팅이었다)
RestTemplate
Spring에서 제공하는 HTTP Client로 REST API를 호출하기 위한 함수를 제공하는 클래스이다.
특징
- HTTP 요청 후 Json, xml, String과 같은 응답을 받을 수 있는 템플릿
- RESTful 형식을 지원한다
- 멀티 스레드와 Blocking 방식 사용
- Blocking I/O 기반의 동기 방식 API
동작방식
- 애플리케이션이 RestTemplate 생성 및 URI, HTTP 메서드 등의 헤더를 담아 요청
- MessageConverter를 이용해 Java Object를 RequestBody에 담을 메시지 형태(Json, xml등)로 변환
- RestTemplate은 ClientHttpRequestFactory에서 ClientHttpRequest를 가져와서 요청을 전달
- ClientHttpRequest가 HTTP 통신으로 요청을 수행
- RestTemplate가 에러 핸들링
- ClientHttpResponse에서 응답 데이터를 가져와 오류있을 경우 처리
- MessageConverter를 이용해 ResponseBody의 메시지를 JavaObject로 변환
- 애플리케이션에 결과값 반환
즉, RestTemplate 통신 과정은 ClientHttpRequestFactory에 위임하여 처리한다는 것을 알 수 있다.
WebClient
블록킹 동기방식인 RestTemplate와 달리 논블락킹 방식이다. 현재는 Spring에서 WebClient의 사용을 강력히 권고하고 있다고 한다.
특징
- 싱글 스레드(코어당 1개의 스레드)와 Non-Blocking 방식 사용
- 이벤트에 반응형으로 동작(Spring React 프레임워크 사용)
- Reactor 기반의 Functional API이다
- RestTemplate과 같이 HTTP 요청 후 응답받을 수 있는 템플릿 역할
Config
자주 사용할 것 같은 문법들만 몇개 작성하였는데, 공식 문서를 참고하는 것이 가장 정확할 듯 하다.
생성
- Static Factory Methods
- WebClient.create()
- WebClient.create(String baseUrl)
- WebClient.builder() Builder 사용
WebClient client = WebClient.builder()
.codecs(configurer -> ... )
.build();
timeouts
연결 관련, read/write, 특정 응답 등에 대해 time out을 설정할 수 있다.
import io.netty.channel.ChannelOption;
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
retrieve()
응답값을 어떻게 가져올지 설정이 가능하다.
WebClient client = WebClient.create("https://example.org");
Mono<ResponseEntity<Person>> result = client.get()
.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
.retrieve()
.toEntity(Person.class);
RequestBody
Mono<Person> personMono = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body(personMono, Person.class)
.retrieve()
.bodyToMono(Void.class);
참고
RestTemplate vs WebClient 실험
WebClient 관련 참고글
WebFlux Docu-WebClient 문법
WebClient 쉽게 이해하기