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 可以使用更少的线程和系统资源来处理更多的逻辑。

WebClientSpring 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

作者:Drazen Nikolic

译者:万想------

送福利啦~ 近期将之前已翻译文章,整理成了PDF。



在公众号后台回复:002即可领取哦~



后续也会不断更新PDF的内容,敬请期待!

Spring WebClient vs. RestTemplate的更多相关文章

  1. 使用 Spring 提供的 restTemplate 完成 Http 服务消费

    RestTemplate 介绍 RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 Http 服务的方法,能够大大提高 ...

  2. Spring Cloud Alibaba - RestTemplate

    Spring Cloud Alibaba - RestTemplate Controller导入依赖和相关属性 @SuppressWarnings("all") @RestCont ...

  3. Spring RESTFul Client – RestTemplate Example--转载

    原文地址:http://howtodoinjava.com/2015/02/20/spring-restful-client-resttemplate-example/ After learning ...

  4. 笔记:Spring Cloud Ribbon RestTemplate 详解

    详细介绍RestTemplate 针对几种不同请求类型和参数类型的服务调用实现,示例代码中的 restTemplate 都是通过Spring 注入方式创建的,相关代码如下: @Autowired pr ...

  5. Spring Boot使用RestTemplate消费REST服务的几个问题记录

    我们可以通过Spring Boot快速开发REST接口,同时也可能需要在实现接口的过程中,通过Spring Boot调用内外部REST接口完成业务逻辑. 在Spring Boot中,调用REST Ap ...

  6. spring boot 注入 restTemplate

    转载自:http://blog.csdn.net/liuchuanhong1/article/details/54631080 package com.chhliu.springboot.restfu ...

  7. Spring web之restTemplate超时问题处理

    问题 项目中有个远程服务因为某些原因会访问不通,于是就在调用的那一步挂起无法结束了. 查看代码 代码大概如下 CloseableHttpClient closeableHttpClient = Htt ...

  8. Spring Boot+Cloud RestTemplate 调用IP或域名

    在SpringBoot+Cloud的项目中,我们使用了自动配置的OAuth2RestTemplate,RestTemplate,但是在使用这些restTemplate的时候,url必须是服务的名称,如 ...

  9. Spring Boot注入RestTemplate ,出现空指针解决办法

    SpringBoot 注入RestTemplate 我看了一下大都是让我们在启动类里面加一个Bean配置代码如下 @Autowired private RestTemplateBuilder buil ...

随机推荐

  1. 打包成war包之后如何读取配置文件

    今天工作开发中遇到一个问题:在idea运行的项目读取配置文件没有问题,打包成war包之后就会报错java.io.FileNotFoundException: class path resource 原 ...

  2. Storm 学习之路(七)—— Storm集成 Redis 详解

    一.简介 Storm-Redis提供了Storm与Redis的集成支持,你只需要引入对应的依赖即可使用: <dependency> <groupId>org.apache.st ...

  3. RocketMQ(6)---发送普通消息(三种方式)

    发送普通消息(三种方式) RocketMQ 发送普通消息有三种实现方式:可靠同步发送.可靠异步发送.单向(Oneway)发送. 注意 :顺序消息只支持可靠同步发送. GitHub地址: https:/ ...

  4. 如何为linux服务器配置DNS解析?

    本文建立在已经搭建好DNS服务器时,为linux机器配置DNS服务器的三种方式. IP地址是网络上标识站点的数字地址,为了方便记忆,采用域名来代替IP地址标识站点地址.DNS(域名解析)就是域名到IP ...

  5. 妹子问我maven是啥?从相亲说起。。

    自从上一篇原创文章: 第一次教妹子安装IDEA 在<java技术之家>公号发表之后,大家的好评如潮,这给了我继续写下去的信心.感谢你们的支持,我会继续努力的. 自从漂亮妹妹加入我们研发团队 ...

  6. 【设计模式】行为型10中介者模式(Mediator Pattern)

    中介者模式(Mediator Pattern)     这里笔者完全参考了:http://www.runoob.com/design-pattern/mediator-pattern.html,案例精 ...

  7. CentOS7 搭建gitlab服务器

    本文介绍如何在CentOS7.2上搭建Gitlab服务器,并简单介绍如何使用. Preface 使用的是CentOS7.2的操作系统,安装当前最新版Gitlab服务器,下载地址:清华大学开源软件镜像站 ...

  8. Python解释器安装教程以及环境变量配置

    Python3.6安装 打开官网:http://www.python.org,下载python3.6.如下图: 下载完成后进行安装.如下图: 验证环境是否配置成功 打开cmd,输入python,按回车 ...

  9. JS中 【“逻辑运算”,“面试题:作用域问题”,“dom对象”】这些问题的意见见解

    1.逻辑运算 ||  &&  ! ||:遇到第一个为true的值就中止并返回 &&:遇到第一个为false的值就中止并返回,如果没有false值,就返回最后一个不是fa ...

  10. BZOJ 3289:Mato的文件管理(莫队算法+树状数组)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3289 题意:…… 思路:求交换次数即求逆序对数.确定了这个之后,先离散化数组.然后在后面插入元素的话 ...