Spring WebClient vs. RestTemplate
1. 简介
本教程中,我们将对比 Spring 的两种 Web 客户端实现 —— RestTemplate 和 Spring 5 中全新的 Reactive 替代方案 WebClient。
2. 阻塞式 vs 非阻塞式客户端
Web 应用中,对其他服务进行 HTTP 调用是一个很常见的需求。因此,我们需要一个 Web 客户端工具。
2.1. RestTemplate 阻塞式客户端
很长一段时间以来,Spring 一直提供 RestTemplate 作为 Web 客户端抽象。在底层,RestTemplate 使用了基于每个请求对应一个线程模型(thread-per-request)的 Java Servlet API。
这意味着,直到 Web 客户端收到响应之前,线程都将一直被阻塞下去。而阻塞代码带来的问题则是,每个线程都消耗了一定的内存和 CPU 周期。
让我们考虑下有很多传入请求,它们正在等待产生结果所需的一些慢服务。
等待结果的请求迟早都会堆积起来。因此,程序将创建很多线程,这些线程将耗尽线程池或占用所有可用内存。由于频繁的 CPU 上下文(线程)切换,我们还会遇到性能下降的问题。
2.2. WebClient 非阻塞式客户端
另一方面,WebClient 使用 Spring Reactive Framework 所提供的异步非阻塞解决方案。
当 RestTemplate 为每个事件(HTTP 请求)创建一个新的 线程 时,WebClient 将为每个事件创建类似于“任务”的东东。幕后,Reactive 框架将对这些 “任务” 进行排队,并仅在适当的响应可用时执行它们。
Reactive 框架使用事件驱动的体系结构。它提供了通过 Reactive Streams API 组合异步逻辑的方法。因此,与同步/阻塞方法相比,Reactive 可以使用更少的线程和系统资源来处理更多的逻辑。
WebClient 是 Spring WebFlux 库的一部分。因此,我们还可以使用流畅的函数式 API 编写客户端代码,并将响应类型(Mono 和 Flux)作为声明来进行组合。
3. 案例对比
为了演示两种方法间的差异,我们需要使用许多并发客户端请求来运行性能测试。在一定数量的并发请求后,我们将看到阻塞方法性能的显著下降。
另一方面,无论请求数量如何,反应式/非阻塞方法都可以提供恒定的性能。
就本文而言,让我们实现两个 REST 端点,一个使用 RestTemplate,另一个使用 WebClient。他们的任务是调用另一个响应慢的 REST Web 服务,该服务返回一个 Tweet List。
首先,我们需要引入 Spring Boot WebFlux starter 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
接下来,这是我们的慢服务 REST 端点:
@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"));
}
3.1. 使用 RestTemplate 调用慢服务
现在,让我们来实现另一个 REST 端点,它将通过 Web 客户端调用我们的慢服务。
首先,我们来使用 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 的同步特性,代码将会阻塞以等待来自慢服务的响应。只有当收到响应后,才会执行此方法中的其余代码。通过日志,我们可以看到:
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!
3.2. 使用 WebClient 调用慢服务
其次,让我们使用 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 生产者后完成方法的执行。一旦结果可用,发布者将开始向其订阅者发送 tweets。注意,调用 /tweets-non-blocking 这个端点的客户端(本例中的 Web 浏览器)也将订阅返回的 Flux 对象。
让我们来观察这次的日志:
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)
注意,此端点的方法在收到响应之前就已完成。
4. 结论
本文中,我们探讨了在 Spring 中使用 Web 客户端的两种不同方式。
RestTemplate 使用 Java Servlet API,因此是同步和阻塞的。相反,WebClient 是异步的,在等待响应返回时不会阻塞正在执行的线程。只有当程序就绪时,才会产生通知。
RestTemplate 仍将会被使用。但在某些情况下,与阻塞方法相比,非阻塞方法使用的系统资源要少得多。因此,在这些情况下,WebClient 不失为是更好的选择。
文中提到的所有代码片段,均可在 GitHub 上找到。
原文:https://www.baeldung.com/spring-webclient-resttemplate
译者:万想------
送福利啦~ 近期将之前已翻译文章,整理成了PDF。
在公众号后台回复:002即可领取哦~
后续也会不断更新PDF的内容,敬请期待!

Spring WebClient vs. RestTemplate的更多相关文章
- 使用 Spring 提供的 restTemplate 完成 Http 服务消费
RestTemplate 介绍 RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 Http 服务的方法,能够大大提高 ...
- Spring Cloud Alibaba - RestTemplate
Spring Cloud Alibaba - RestTemplate Controller导入依赖和相关属性 @SuppressWarnings("all") @RestCont ...
- Spring RESTFul Client – RestTemplate Example--转载
原文地址:http://howtodoinjava.com/2015/02/20/spring-restful-client-resttemplate-example/ After learning ...
- 笔记:Spring Cloud Ribbon RestTemplate 详解
详细介绍RestTemplate 针对几种不同请求类型和参数类型的服务调用实现,示例代码中的 restTemplate 都是通过Spring 注入方式创建的,相关代码如下: @Autowired pr ...
- Spring Boot使用RestTemplate消费REST服务的几个问题记录
我们可以通过Spring Boot快速开发REST接口,同时也可能需要在实现接口的过程中,通过Spring Boot调用内外部REST接口完成业务逻辑. 在Spring Boot中,调用REST Ap ...
- spring boot 注入 restTemplate
转载自:http://blog.csdn.net/liuchuanhong1/article/details/54631080 package com.chhliu.springboot.restfu ...
- Spring web之restTemplate超时问题处理
问题 项目中有个远程服务因为某些原因会访问不通,于是就在调用的那一步挂起无法结束了. 查看代码 代码大概如下 CloseableHttpClient closeableHttpClient = Htt ...
- Spring Boot+Cloud RestTemplate 调用IP或域名
在SpringBoot+Cloud的项目中,我们使用了自动配置的OAuth2RestTemplate,RestTemplate,但是在使用这些restTemplate的时候,url必须是服务的名称,如 ...
- Spring Boot注入RestTemplate ,出现空指针解决办法
SpringBoot 注入RestTemplate 我看了一下大都是让我们在启动类里面加一个Bean配置代码如下 @Autowired private RestTemplateBuilder buil ...
随机推荐
- 05 div的嵌套
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Unity 通用透明物体漫反射Shader(双面渲染&多光源&光照衰减&法线贴图&凹凸透明度控制)
Shader "MyUnlit/AlphaBlendDiffuse" { Properties { _Color("Color Tint(贴图染色)",Colo ...
- Angular4.0从入门到实战打造在线竞拍网站学习笔记之一--组件
Angular4.0基础知识之组件 Angular4.0基础知识之路由 Angular4.0依赖注入 Angular4.0数据绑定&管道 最近搞到手了一部Angular4的视频教程,这几天正好 ...
- C# RESTful API 访问辅助类
REST 全称是 Representational State Transfer,有人说它是一种风格,并非一种标准,个人觉得挺有道理.它本身并没有创造新的技术.组件与服务,更像是告诉大家如何更好地使用 ...
- 小白也能看懂的 Laravel 核心概念讲解
自动依赖注入 什么是依赖注入,用大白话将通过类型提示的方式向函数传递参数. 实例 1 首先,定义一个类: /routes/web.php class Bar {} 假如我们在其他地方要使用到 Bar ...
- Github项目备份与更新
需求 假如现在想对使用到的一些Github上的开源组件进行备份,采用自建Gitlab服务器的方式进行备份保存,并且组件需定时保持与Github更新. 总体步骤 组件备份- 整体步骤如下: a.搭建gi ...
- QDomDocument 读取和编辑xml文件
Qt中几种操作xml的方式 流方式 sax方式 dom方式 初学时,我常常采用流方式读取xml,该方式简单直观,容易理解.之后遇到了需要修改xml并重新写回的情况,流方式就显得捉襟见肘了. sax方式 ...
- Java中session与application的异同
客户端的session 其实是标记了你的请求来自哪个浏览器 问题1:永远都一样吗? 答:重启了浏览器,你的session id就改变了, 结果会导致,再无法取回原来在服务端保存的数据. 问题2:假设客 ...
- JSON.stringify() 的深入理解
目录 序言 语法 深入理解 序言 最近在看<你所不知道的javascript>[中卷]一书,第一部分是类型和语法.本文是基于这部分的产物.在强制类型转换->抽象值操作-> to ...
- [ZJOI2008]杀蚂蚁antbuster 题解
一个题目的可读版本:https://www.zybuluo.com/Jerusalem/note/221811 这两天做的又一道大模拟题,感觉这玩意有毒,会上瘾啊…… 比起猪国杀这道题真心不知道高到哪 ...