백앤드 개발일지/스프링부트

[webflux] webclient 이슈 정리

giron 2022. 1. 4. 16:05
728x90

대표적으로 외부 api를 호출하는 방식에 resttemplate이 있는데 이것은 동기 방식을 이용한 방법이고, WebClient가 비동기를 이용한 방식이다. 공식문서를 보면 스프링 5부터는 webClient사용을 더 추천하고 있다. 또한 restTemplate은 곧 deprecated 된다고 한다. 공통점으로는 둘 다 Http client에서 사용된다는 것이다.

 

RestTemplate

RestTemplate은 Multi-Thread와 Blocking방식을 사용합니다. 

Thread pool은 요청자 어플리케이션 구동 시에 미리 만들어 놓습니다.

Request는 먼저 Queue에 쌓이고 가용한 스레드가 있으면 그 스레드에 할당되어 처리됩니다. 

즉, 1 요청 당 1 스레드가 할당됩니다.

각 스레드에서는 Blocking방식으로 처리되어 응답이 올 때까지 그 스레드는 다른 요청에 할당될 수 없습니다.

 

Spring WebClient

Spring WebClient는 Single Thread와 Non-Blocking방식을 사용합니다. 

 

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

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

 

<반환 타입>

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

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

그렇게 된다면 main스레드에서 처리하기 때문에 사용하면 안 된다.

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

 

Spring MVC/Webflux - Flux, Mono를 사용하는 환경에서는 절대(Never) block을 사용해서는 안된다. 그냥 단순히 controller 메서드에서 reactive type을 넘기는 식으로 진행해야 한다.

 

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

 

간단한 예제

service Class

exchange()는 상태값이랑 헤더랑 바디도 가져오고 - 메모리 누수 가능이 있다.

retrieve()는 응답의 바디만 가져온다.

Controller class
bean 등록을 한다

localhost:8080/v1/events를 호출하면 받아온 api를 통해서 결과가 잘 나온다!

이슈 발생

No serializer found for class com.bunjang.cote.dto.Event and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0])

serialize 하는 과정에서 멤버 변수가 private이라서 발생한다고 한다. getter와 setter를 설정해줬는데도 발생해서 의문이다. 생성자도 public으로 해봤지만 계속 발생했다..🤔🤔🤔 

해결법

  1. application.property에 아래의 내용을 추가해주면 된다. 
  2. jackson.serialization.fail-on-empty-beans = false​
  3. dto클래스
    dto클래스에 JsonAutoDetect를 추가해서 ANY옵션을 주어도 된다.
728x90