WebClient 非阻塞客戶端 RestTemplate 阻塞式客戶端


收到多個客戶端請求后,阻塞方法的性能顯著下降。

而 Reactive 非阻塞方法的表現應該與請求數量無關,性能穩定

添加 Spring Boot WebFlux Starter 依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

耗時比較

@GetMapping("/slow-service-tweets")
private List<Tweet> getAllTweets() {
    Thread.sleep(2000L); // 延遲
    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;
}

由於 RestTemplate 是同步調用,調用 Endpoint 時代碼將進入阻塞等待被調用的耗時服務響應。只有在收到響應后,才會執行方法中的后續代碼,日志如下:

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;
}

  

WebClient 返回 Flux publisher 后就執行完成了。結果就緒時,publisher 會向訂閱者發送推文列表。注意:客戶端(這里指 Web 瀏覽器)調用/tweets-non-blocking Endpoint 也可以訂閱 Flux 對象。 這個 Endpoint 方法在收到響應前就已執行完成。

 

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) 

 總結:

這篇文章討論了 Spring 中使用 Web Client 的兩種不同方式。

 

RestTemplate 采用 Java Servlet API,因而是阻塞式同步調用。相反,WebClient 是異步的,等待響應的同時不會阻塞正在執行的線程。只有在響應結果准備就緒時,才會發起通知。

 

RestTemplate 仍然有用武之地。非阻塞模式在某些場景下比阻塞方法占用系統資源要少得多,這時 WebClient 是一種更好的選擇

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM