Spring

Spring RestTemplate vs WebClient

joaa 2024. 2. 27. 10:25

๐ŸŽˆ RestTemplate vs Webclient

RestTemplate
thread-per-request ๋ชจ๋ธ์— ๊ธฐ๋ฐ˜ํ•˜๋Š” Java Servlet API๋ฅผ ์‚ฌ์šฉํ•จ.-> Synchronous & Blocking
ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‘๋‹ต์„ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ thread๊ฐ€ ๋ธ”๋Ÿญ ์ƒํ…Œ์ž„. ๋ฉ”๋ชจ๋ฆฌ์™€ CPU cycle์„ ์†Œ๋ชจํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ธํ•œ block code์˜ ๋‹จ์ ์ด ๋ฐœ์ƒํ•จ.


๊ฒฐ๊ณผ์ ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋งŽ์€ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ด๊ฒƒ์€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ชจ๋‘ ์ ์œ ํ•˜๊ฑฐ๋‚˜ ์Šค๋ ˆ๋“œ ํ’€์„ ์†Œ๋ชจํ•  ์ˆ˜ ์žˆ์Œ.

 

WebClient
Spring Reactive ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” Asynchronous, non-blocking ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•จ.

RestTemplate์€ ๊ฐ HTTP ์š”์ฒญ๋งˆ๋‹ค thread๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , WebClient๋Š” HTTP ์š”์ฒญ๋งˆ๋‹ค "task"๋ฅผ ์ƒ์„ฑํ•จ. Reactive ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ๊ทธ task๋“ค์„ ํ์— ๋„ฃ์—ˆ๋‹ค๊ฐ€ ์ ์ ˆํ•œ ์‘๋‹ต์ด ๊ฐ€๋Šฅํ•  ๋•Œ task๋ฅผ ์‹คํ–‰ํ•จ.

 

Reactive ํ”„๋ ˆ์ž„์›Œํฌ๋Š” event-driven ์•„ํ‚คํ…์ณ๋ฅผ ์‚ฌ์šฉํ•ด์„œ Reactive Streams API๋ฅผ ํ†ตํ•ด asynchronous logic์„ ์งœ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•จ. ๊ฒฐ๊ณผ์ ์œผ๋กœ Reacitveํ•œ ์ ‘๊ทผ์€ synchronous/blocking ๋ฐฉ๋ฒ•๋ณด๋‹ค ์ ์€ ์Šค๋ ˆ๋“œ์™€ ์‹œ์Šคํ…œ ์ž์›์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋” ๋งŽ์€ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Œ.

 

WebClient๋Š” Srping WebFlux ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋จ. ๋”ฐ๋ผ์„œ ๋ฐ˜์‘ํ˜•(Mono ๋ฐ Flux)์„ ์„ ์–ธ์  ๊ตฌ์„ฑ์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋Šฅ์ ์ด๊ณ  ์œ ์ฐฝํ•œ API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ์Œ.

 

Spring5.0 ๋ฒ„์ „๋ถ€ํ„ฐ RestTemplate์˜ ๋Œ€์•ˆ์œผ๋กœ WebClient ์‚ฌ์šฉ์„ ๊ถŒ๊ณ ํ•จ.



WebClient์˜ ํŠน์ง•

  • Non-blocking I/O
  • Reactive Streams back pressure
  • High concurrency with fewer hardware resources
  • Functional-style, fluent API that takes advantage of Java 8 lambdas
  • Synchronous and asynchronous interactions
  • Streaming up to or streaming down from a server




์˜ˆ์‹œ๋ฅผ ํ†ตํ•œ RestTemplate WebClient ๋น„๊ต

java
@GetMapping("/slow-service-tweets")
private List<Tweet> getAllTweets() {
    Thread.sleep(2000L); // delay
    return Arrays.asList(
      new Tweet("RestTemplate rules", "@user1"),
      new Tweet("WebClient is better", "@user2"),
      new Tweet("OK, both are useful", "@user1"));
}



RestTemplate๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ

@GetMapping("/tweets-blocking")
public List<Tweet> getTweetsBlocking() {
    log.info("Starting BLOCKING Controller!");
    final String uri = getSlowServiceUri();

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<List<Tweet>> response = restTemplate.exchange(
      uri, HttpMethod.GET, null,
      new ParameterizedTypeReference<List<Tweet>>(){});

    List<Tweet> result = response.getBody();
    result.forEach(tweet -> log.info(tweet.toString()));
    log.info("Exiting BLOCKING Controller!");
    return result;
}

๊ฒฐ๊ณผ

Starting BLOCKING Controller!
Tweet(text=RestTemplate rules, username=@user1)
Tweet(text=WebClient is better, username=@user2)
Tweet(text=OK, both are useful, username=@user1)
Exiting BLOCKING Controller!



WebClient๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ

@GetMapping(value = "/tweets-non-blocking", 
            produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Tweet> getTweetsNonBlocking() {
    log.info("Starting NON-BLOCKING Controller!");
    Flux<Tweet> tweetFlux = WebClient.create()
      .get()
      .uri(getSlowServiceUri())
      .retrieve()
      .bodyToFlux(Tweet.class);

    tweetFlux.subscribe(tweet -> log.info(tweet.toString()));
    log.info("Exiting NON-BLOCKING Controller!");
    return tweetFlux;
}

๊ฒฐ๊ณผ

Starting NON-BLOCKING Controller!
Exiting NON-BLOCKING Controller!
Tweet(text=RestTemplate rules, username=@user1)
Tweet(text=WebClient is better, username=@user2)
Tweet(text=OK, both are useful, username=@user1)

 

๐ŸŽˆ Reactive Programming์ด๋ž€?


The introduction to Reactive Programming you've been missing · GitHub

๐ŸŽˆ Reactive Stream

์•„๋ž˜ 4๊ฐ€์ง€ Component๋กœ ๊ตฌ์„ฑ๋จ

  1. Publisher
  2. Subscriber
  3. Subscription
  4. Processor

Publisher๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์‚ฐํ•˜๊ณ , Subscriber๊ฐ€ ๋“ฑ๋ก๋˜๊ธฐ ์ „๊นŒ์ง€ ์•„๋ฌด๋Ÿฐ ์ผ๋„ ํ•˜์ง€ ์•Š์Œ. Publisher๋Š” Subscriber๊ฐ€ ๋“ฑ๋ก๋˜๋Š” ์‹œ์ ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ pushํ•จ. 

 

Spring Webflux์—์„œ ์‚ฌ์šฉํ•˜๋Š” reactive libaray๊ฐ€ Reactor์ด๊ณ  Reactor๊ฐ€ Reactive Streams์˜ ๊ตฌํ˜„์ฒด!

๋ฆฌ์•กํ„ฐ๋Š” Mono์™€ Flux 2๊ฐ€์ง€ ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ์ŠคํŠธ๋ฆผ์„ ์ •์˜ํ•จ. 

WebFlux์—์„œ๋Š” ๋ชจ๋“  ์‘๋‹ต์„ Mono ํ˜น์€ Flux์— ๋‹ด์•„์„œ ๋ฐ˜ํ™˜ํ•ด์ฃผ์–ด์•ผ ํ•จ. 





๐ŸŽˆ Mono์™€ Flux

Flux์™€ Mono๋Š” Reactor ๊ฐ์ฒด์ด๋ฉฐ, ์ฐจ์ด์ ์€ ๋ฐœํ–‰ํ•˜๋Š” ๋ฐ์ดํ„ฐ ๊ฐฏ์ˆ˜

- Flux: 0~N๊ฐœ์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ




- Mono: 0~1๊ฐœ์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ



Reactor์—์„œ ์ œ๊ณตํ•˜๋Š” ๋‹ค์–‘ํ•œ operator๋“ค์˜ ์กฐํ•ฉ์„ ํ†ตํ•ด ์ŠคํŠธ๋ฆผ์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Œ. 
operator๋Š” ๋งค์šฐ ๋งŽ์œผ๋ฏ€๋กœ ๋•Œ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ operator๋ฅผ ์ ์šฉํ•ด์•ผํ•จ. 


 

 

 

 

Spring WebClient vs. RestTemplate | Baeldung

[spring] WebFlux๋ž€ + Reactor ๊ฐ์ฒด๋ž€ (Mono<> ์™€ Flux<>) (tistory.com)

[Spring WebFlux] 0. ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์†Œ๊ฐœ — ๐Ÿ› HOON DEVLog (tistory.com)

https://ddoriya.tistory.com/entry/RestTemplate-VS-WebClient

[Spring] WebFlux์˜ ๊ฐœ๋… / Spring MVC์™€ ๊ฐ„๋‹จ๋น„๊ต (tistory.com)