RestTemplate에서 WebClient로 리팩토링해보기

cmsskkk·2022년 6월 11일
1

TIL

목록 보기
11/11

RestTemplate -> WebClient 리팩토링

참고자료

리팩토링 계기

  • 프로젝트 기능 요구사항 중 사용자의 GPS좌표를 기준으로 인기 여행지에 대한 거리 혹은 걸리는 시간을 반환하도록 하는 기능이 있다.
  • 단순하게 좌표와 좌표에 대한 직선거리, 그리고 그 직선거리를 임의로 정한 평균시속으로 시간을 계산해서 반환하지 않고
    실제 자동차로 가는 거리 및 시간을 반환하고자 했다.
  • 처음에는 사용법이 간단하고, 한번 사용해봤던 restTemplate으로 일단 기능을 구현했었는데,
    kakao-navi api를 총 8번 순차적으로(동기적으로) 호출했기에 API 응답속도가 10초 가까이 나오게 되었다.

WebClient를 통해서 비동기적으로 처리해보기로~

1. WebClient를 Bean으로 등록하기

  • baseUrl과 필요한 api를 사용하기 위한 secretKey를 비롯한 header를 설정해서 bean으로 등록한다.
  • bean의 이름을 지정해 준 이유는 Oauth에 사용할 webClient또한 bean으로 등록해두었기 때문이다.

2. WebClient로 api 호출

  • webClient를 통해서 api를 호출하는 로직이다.
  • 요청할 메서드와 baseurl은 지정해주었기 때문에, path와 query parameter를 uriBuilder를 통해서 uri를 지정해준다.
  • .bodyToMono(NaviResponse.class);
  • api를 반환받을 타입은 NaviResponse(ObjectMapper가 자동적으로 파싱해줄 수 있도록 필드 등 Property를 설정해주었다.)
  • mono와 flux는 데이터 스트림의 갯수에 따라 사용해야한다.

3. 비동기로 바꾸기

  • restTemplate를 사용할 때와 동일하게 district(지역의 좌표를 담은 enum)를 for문으로 돌면서 현재 좌표에 대해서 거리 및 시간을 반환토록 했다.
  • 동기적으로 처리하지않고, Mono객체의 subscribe 메서드를 통해서 Map에 지역의 이름과 반환객체를 담도록 했다.
  • CountDownLatch가 없다면, NaviResponse에 응답 값이 들어오기전에 다른 메서드들이 실행되기 때문에, api 응답에 빈 리스트만 반환된다.
  • CountDownLatch.await() 를 통해서 모든 스레드가 일 처리를 완료할 때까지(응답 값을 채울때까지) 기다리게 할 수 있다.
  • NaviResponseMono.log() 메서드를 통해서 비동기 처리에대한 log를 확인할 수 있다.
2022-06-11 19:21:04.750  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.1                   : | onSubscribe([Fuseable] MonoFlatMap.FlatMapMain)
2022-06-11 19:21:04.751  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.1                   : | request(unbounded)
2022-06-11 19:21:05.233  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.2                   : | onSubscribe([Fuseable] MonoFlatMap.FlatMapMain)
2022-06-11 19:21:05.233  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.2                   : | request(unbounded)
2022-06-11 19:21:05.234  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.3                   : | onSubscribe([Fuseable] MonoFlatMap.FlatMapMain)
2022-06-11 19:21:05.234  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.3                   : | request(unbounded)
2022-06-11 19:21:05.235  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.4                   : | onSubscribe([Fuseable] MonoFlatMap.FlatMapMain)
2022-06-11 19:21:05.235  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.4                   : | request(unbounded)
2022-06-11 19:21:05.235  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.5                   : | onSubscribe([Fuseable] MonoFlatMap.FlatMapMain)
2022-06-11 19:21:05.235  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.5                   : | request(unbounded)
2022-06-11 19:21:05.236  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.6                   : | onSubscribe([Fuseable] MonoFlatMap.FlatMapMain)
2022-06-11 19:21:05.236  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.6                   : | request(unbounded)
2022-06-11 19:21:05.237  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.7                   : | onSubscribe([Fuseable] MonoFlatMap.FlatMapMain)
2022-06-11 19:21:05.237  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.7                   : | request(unbounded)
2022-06-11 19:21:05.237  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.8                   : | onSubscribe([Fuseable] MonoFlatMap.FlatMapMain)
2022-06-11 19:21:05.237  INFO 44982 --- [nio-8080-exec-1] reactor.Mono.FlatMap.8                   : | request(unbounded)
2022-06-11 19:21:05.693  INFO 44982 --- [ctor-http-nio-2] reactor.Mono.FlatMap.1                   : | onNext(NaviResponse(infos=[NaviInfo(code=0, summary=Summary(distance=7073.0, duration=1233.0))]))
2022-06-11 19:21:05.695  INFO 44982 --- [ctor-http-nio-2] reactor.Mono.FlatMap.1                   : | onComplete()
2022-06-11 19:21:06.212  INFO 44982 --- [ctor-http-nio-4] reactor.Mono.FlatMap.3                   : | onNext(NaviResponse(infos=[NaviInfo(code=0, summary=Summary(distance=42369.0, duration=4560.0))]))
2022-06-11 19:21:06.212  INFO 44982 --- [ctor-http-nio-4] reactor.Mono.FlatMap.3                   : | onComplete()
2022-06-11 19:21:06.229  INFO 44982 --- [ctor-http-nio-3] reactor.Mono.FlatMap.2                   : | onNext(NaviResponse(infos=[NaviInfo(code=0, summary=Summary(distance=61847.0, duration=4763.0))]))
2022-06-11 19:21:06.230  INFO 44982 --- [ctor-http-nio-3] reactor.Mono.FlatMap.2                   : | onComplete()
2022-06-11 19:21:06.517  INFO 44982 --- [ctor-http-nio-5] reactor.Mono.FlatMap.4                   : | onNext(NaviResponse(infos=[NaviInfo(code=0, summary=Summary(distance=227785.0, duration=9247.0))]))
2022-06-11 19:21:06.517  INFO 44982 --- [ctor-http-nio-5] reactor.Mono.FlatMap.4                   : | onComplete()
2022-06-11 19:21:06.635  INFO 44982 --- [ctor-http-nio-7] reactor.Mono.FlatMap.6                   : | onNext(NaviResponse(infos=[NaviInfo(code=0, summary=Summary(distance=221692.0, duration=10417.0))]))
2022-06-11 19:21:06.636  INFO 44982 --- [ctor-http-nio-7] reactor.Mono.FlatMap.6                   : | onComplete()
2022-06-11 19:21:06.827  INFO 44982 --- [ctor-http-nio-1] reactor.Mono.FlatMap.8                   : | onNext(NaviResponse(infos=[NaviInfo(code=0, summary=Summary(distance=343916.0, duration=13146.0))]))
2022-06-11 19:21:06.827  INFO 44982 --- [ctor-http-nio-1] reactor.Mono.FlatMap.8                   : | onComplete()
2022-06-11 19:21:07.234  INFO 44982 --- [ctor-http-nio-8] reactor.Mono.FlatMap.7                   : | onNext(NaviResponse(infos=[NaviInfo(code=0, summary=Summary(distance=354964.0, duration=14933.0))]))
2022-06-11 19:21:07.235  INFO 44982 --- [ctor-http-nio-8] reactor.Mono.FlatMap.7                   : | onComplete()
2022-06-11 19:21:07.310  INFO 44982 --- [ctor-http-nio-6] reactor.Mono.FlatMap.5                   : | onNext(NaviResponse(infos=[NaviInfo(code=0, summary=Summary(distance=406501.0, duration=15768.0))]))
2022-06-11 19:21:07.311  INFO 44982 --- [ctor-http-nio-6] reactor.Mono.FlatMap.5                   : | onComplete()

결과

응답 속도 9.xx초에서 2.xx초 이내로

회고

  • 아직 적절한 활용 혹은 더 좋은 성능 개선의 여지가 많다.
  • 사용하지않은 메서드와 사용법이 정말 많다.
  • 메서드 분리 또는 stream를 활용해보는 등 코드 리팩토링 또한 필요하다.
  • 단순히 한번 사용할 때는 resttemplate가 편하지만, 재사용할때는 webClient가 더 편하고, 지원하는 기능 또한 많다. (사용법이 편하다고 webclient를 사용하는 것은 webFlux 디펜던시가 무거운 편이기 때문에 사용을 고려해봐야한다.)
  • Java 11에 추가된 HttpClient와 CompleatbleFuture등을 활용해서도 비동기로 처리할 수 있다.
profile
차곡차곡

1개의 댓글

comment-user-thumbnail
2022년 6월 12일

내가 좋아요 를 눌렀다 이말이야~

답글 달기