Spring

[Spring] RestTemplate과 WebClient 이해하기

별토끼. 2021. 9. 12. 19:24
반응형

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

동작방식

  1. 애플리케이션이 RestTemplate 생성 및 URI, HTTP 메서드 등의 헤더를 담아 요청
  2. MessageConverter를 이용해 Java Object를 RequestBody에 담을 메시지 형태(Json, xml등)로 변환
  3. RestTemplate은 ClientHttpRequestFactory에서 ClientHttpRequest를 가져와서 요청을 전달
  4. ClientHttpRequest가 HTTP 통신으로 요청을 수행
  5. RestTemplate가 에러 핸들링
  6. ClientHttpResponse에서 응답 데이터를 가져와 오류있을 경우 처리
  7. MessageConverter를 이용해 ResponseBody의 메시지를 JavaObject로 변환
  8. 애플리케이션에 결과값 반환

즉, RestTemplate 통신 과정은 ClientHttpRequestFactory에 위임하여 처리한다는 것을 알 수 있다.

WebClient

블록킹 동기방식인 RestTemplate와 달리 논블락킹 방식이다. 현재는 Spring에서 WebClient의 사용을 강력히 권고하고 있다고 한다.

특징

  • 싱글 스레드(코어당 1개의 스레드)와 Non-Blocking 방식 사용
  • 이벤트에 반응형으로 동작(Spring React 프레임워크 사용)
  • Reactor 기반의 Functional API이다
  • RestTemplate과 같이 HTTP 요청 후 응답받을 수 있는 템플릿 역할

Config

자주 사용할 것 같은 문법들만 몇개 작성하였는데, 공식 문서를 참고하는 것이 가장 정확할 듯 하다.

생성

  1. Static Factory Methods
    • WebClient.create()
    • WebClient.create(String baseUrl)
  2. 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 쉽게 이해하기

반응형