WebClient

WebClient?

Spring WebFlux๋Š” HTTP ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. WebClient ๋Š” ๋ฐ˜์‘ํ˜• ๋ฐฉ์‹์œผ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ๊ณ  ๋น„๋™๊ธฐ ๋ฐ Non-Blocking ํ†ต์‹ ์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Spring 5.0 ๋ถ€ํ„ฐ ์ง€์›

  • ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ๋ฐฉ์‹

  • Non-Blocking ๋ฐฉ์‹, ๋™๊ธฐ/๋น„๋™๊ธฐ ๋ชจ๋‘ ์ง€์›

  • Reactor ๊ธฐ๋ฐ˜์˜ Functional API (Mono, Flux)

WebClient๋Š” ์š”์ฒญ์„ ๋‚˜ํƒ€๋‚ด๊ณ  ์ „์†กํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๋นŒ๋” ๋ฐฉ์‹์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์™ธ๋ถ€ API๋กœ ์š”์ฒญ์„ ํ•  ๋•Œ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํƒ€์ž…์˜ ์ „์†ก๊ณผ ์ˆ˜์‹ ์„ ํ•ฉ๋‹ˆ๋‹ค.

WebClient ์ด์ 

WebClient๋Š” ๋™๊ธฐ, ๋น„๋™๊ธฐ ํ˜ธ์ถœ์„ ๋ชจ๋‘ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. WebClient๋Š” Non-Blocking ๋ฐฉ์‹์œผ๋กœ, ํ˜ธ์ถœ๋œ ์‹œ์Šคํ…œ์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ธ”๋กœํ‚น/๋…ผ๋ธ”๋กœํ‚น์€ ์ œ์–ด๊ถŒ ๋ฐ˜ํ™˜์— ์ค‘์ ์„ ๋‘๊ณ , ๋™๊ธฐ/๋น„๋™๊ธฐ๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ ์ฃผ๋Š”์ง€์— ์ค‘์ ์„ ๋‘ก๋‹ˆ๋‹ค.

๋™๊ธฐ๋Š” ์ž‘์—… ๊ฒฐ๊ณผ๊ฐ’์„ ์ง์ ‘ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ˜๋ฉด, ๋น„๋™๊ธฐ๋Š” ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ›์œผ๋ฉด ์–ด๋–ป๊ฒŒ ํ• ์ง€์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋ฏธ๋ฆฌ ์ •์˜ํ•ด๋‘ก๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : https://gngsn.tistory.com/154

WebClient์—์„œ ๊ฐ€๋Šฅํ•œ ๋น„๋™๊ธฐ ๋ฐฉ์‹์˜ Non-Blocking ๋ฐฉ์‹์€ ๊ฐ์ž ํ•  ์ผ์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ํ•„์š”ํ•œ ์‹œ์ ์— ๊ฐ์ž ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

Blocking ๋ฐฉ์‹์˜ RestTemplate๊ณผ Non-Blocking ๋ฐฉ์‹์˜ WebClient์˜ ์„ฑ๋Šฅ ๋น„๊ต

์ถœ์ฒ˜ : https://dzone.com/articles/raw-performance-numbers-spring-boot-2-webflux-vs-s

๊ทธ๋ž˜ํ”„์˜ Boot1์€ RestTemplate์„, Boot2๋Š” WebClient๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

๋™์‹œ ์‚ฌ์šฉ์ž ์ˆ˜๊ฐ€ 1,000๋ช… ๋ฏธ๋งŒ์ผ ๊ฒฝ์šฐ Boot1๊ณผ Boot2 ๋ชจ๋‘ ๋น„์Šทํ•œ ์‘๋‹ต์†๋„๋ฅผ ๋‚ด์ง€๋งŒ, ๋™์‹œ ์‚ฌ์šฉ์ž ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์†๋„ ์ฐจ์ด๊ฐ€ ๋ฒŒ์–ด์ง€๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

WebClient ์ƒ์„ฑ

์˜์กด์„ฑ ์ถ”๊ฐ€

build.gradle

dependency์— ์œ„ ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

WebClient๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹จ์ˆœ create()ํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ, option์„ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” Builder๋ฅผ ํ™œ์š”ํ•œ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

create()

๋‹จ์ˆœํ•˜๊ฒŒ WebClient์˜ Default Setting์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ณ , ์š”์ฒญํ•  URI์™€ ํ•จ๊ป˜ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Builder()

Builder๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MaxInMemorySize ์„ค์ •

Spring Webflux๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฉ”๋ชจ๋ฆฌ ์ด์Šˆ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”๋ชจ๋ฆฌ ๋ฒ„ํผ ์‚ฌ์ด์ฆˆ๋ฅผ Default๋กœ 256KB๋กœ ์ œํ•œํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„ ์„ค์ •์„ ํ†ตํ•ด ์ตœ๋Œ€ ๋ฒ„ํผ ์‚ฌ์ด์ฆˆ๋ฅผ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

TimeOut ์„ค์ •

Connect TimeOut๊ณผ Read TimeOut, Write TimeOut์„ ๋ชจ๋‘ ์ง€์ •ํ•ด์„œ HttpClient ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Config

์œ„ ๋‚ด์šฉ๋“ค์„ ์ ์šฉํ•˜์—ฌ Config๋ฅผ ํ†ตํ•ด Bean์œผ๋กœ ๋งŒ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Bean์œผ๋กœ ๋“ฑ๋กํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๋ฒˆ ๋นŒ๋“œํ•œ ๋’ค์— WebClient๋Š” ํ•ด๋‹น ์˜ต์…˜์œผ๋กœ ๊ณ ์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ WebClient๋ฅผ Default Setting๊ณผ ๋‹ค๋ฅด๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด mutate()๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

mutate()

Request

GET

Flux

Employee ๊ฐ์ฒด ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ๋ฐ›๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Mono

ID๋ฅผ ํ†ตํ•ด Employee ๊ฐ์ฒด ํ•œ ๊ฐœ๋ฅผ ์กฐํšŒํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

POST

.body(Mono.just(empl), Employee.class) ์ฝ”๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋Š” empl์˜ ํƒ€์ž…์ด Employee๋ผ๋Š” ํด๋ž˜์Šค์ž„์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ, POST ํ›„ ๋ฐ›์„ body๊ฐ€ ์—†๋‹ค๋ฉด bodyToMono(Void.class) ๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Response

์š”์ฒญ ํ•œ ํ›„์—๋Š” ์‘๋‹ต์„ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‘๋‹ต์„ ๋ฐ›์„ ๋•Œ์—๋Š” ์•„๋ž˜์˜ ๋‘ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ ์ค‘ ์ ์ ˆํ•œ ๊ฒƒ์„ ์„ ํƒํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • retrieve() : body๋ฅผ ๋ฐ›์•„ ๋””์ฝ”๋”ฉํ•˜๋Š” ๋ฉ”์„œ๋“œ

  • exchange() : ClientResponse๋ฅผ ์ƒํƒœ๊ฐ’๊ณผ ํ—ค๋”๋ฅผ ํ•จ๊ป˜ ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”์„œ๋“œ

exchange()๋ฅผ ํ†ตํ•ด ์„ธ์„ธํ•œ ์ž‘์—…์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๊ฐ€๋Šฅ์„ฑ ๋•Œ๋ฌธ์— retrieve()๋ฅผ ๊ถŒ๊ณ ํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ Request ํŒŒํŠธ์—์„œ Mono ๊ฐ์ฒด๋Š” 0-1๊ฐœ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ์ฒด์ด๊ณ , Flux ๋Š” 0-N๊ฐœ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

retrieve()

retrieve๋ฅผ ์‚ฌ์šฉํ•œ ํ›„์˜ ๋ฐ์ดํ„ฐ๋Š” ๋‘ ๊ฐ€์ง€ ํ˜•ํƒœ๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

toEntity()

status, headers, body๋ฅผ ํฌํ•จํ•˜๋Š” ResponseEntity ํƒ€์ž…์œผ๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค.

toMono(), toFlux()

body์˜ ๋ฐ์ดํ„ฐ๋กœ๋งŒ ๋ฐ›๊ณ ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

exchangeToXXXX()

Mono<>, Flux<> ์‚ฌ์šฉ

Mono<>, Flux<>๋Š” Blocking ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ ์ž ํ•˜๋ฉด .block() , Non-Blocking ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ ์ž ํ•˜๋ฉด .subscribe() ๋ฅผ ํ†ตํ•ด callback ํ•จ์ˆ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ErrorHandling

retrieve()

retrieve๋Š” 1XX, 2XX, 3XX StatusCode๋ณ„๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์ฐธ๊ณ 

https://oliveyoung.tech/blog/2022-11-10/oliveyoung-discovery-premium-webclient/

https://gngsn.tistory.com/154

Last updated