java get resttemplate 请求传递数组_Spring WebClient 与 RestTemplate 比较

(给ImportNew加星标,提高Java技能)

编译:ImportNew/唐尤华

www.baeldung.com/spring-webclient-resttemplate

1. 导读

在这篇教程中,我们将对比两种 Spring Web 客户端实现,RestTemplate 和新的 Spring 5 Reactive WebClient。

2. 阻塞式客户端 vs 非阻塞客户端

在 Web 应用程序中,向其他服务发起 HTTP 调用是常见需求。因此,需要一个 Web 客户端工具。

2.1. RestTemplate 阻塞式客户端

长期以来,Spring 一直把 RestTemplate 作为默认 Web 客户端。RestTemplate 使用 Java Servlet API,这种模型在底层会为每个请求分配处理线程

这意味着线程会一直保持阻塞,直到 Web 客户端收到响应。阻塞式模型的问题在于每个线程都会消耗大量内存和 CPU 资源。

让我们考虑这样的情况:系统收到大批请求时,等待某些服务返回结果,而这些服务本身执行缓慢。

结果,等待的请求会发生堆积。应用程序将创建许多线程,耗尽线程池并占掉所有可用内存。还可能因为 CPU 上下文(线程)频繁切换导致性能下降。

2.2. WebClient 非阻塞客户端

另一种 WebClient 方案,利用 Spring Reactive 框架提供异步、非阻塞式解决方案。

RestTemplate 为每个事件(HTTP 调用)创建一个新线程,而 WebClient 为每个事件创建类似 task 的结构。Reactive 框架会在后台对这些 task 进行排队,且只在响应结果就绪后才开始执行。

Reactive 框架采用事件驱动,通过Reactive Streams API 实现异步逻辑。相比同步阻塞式调用,Reactive 方法用更少的线程和系统资源处理了更多业务逻辑。

Webclient 是 Spring WebFlux 开发库的一部分。因此,写客户端代码时,还可以应用函数式编程与流式 API,支持 Reactive 类型(Mono 和 Flux)

3. 实例比较

为了展示两种方法差异,需要多客户端并行请求进行性能测试。可以看到,收到多个客户端请求后,阻塞方法的性能显著下降。

而 Reactive 非阻塞方法的表现应该与请求数量无关,性能稳定。

这里会实现两个 REST Endpoint:一个用 RestTemplate,另一个用 WebClient。它们的任务是调用另一个耗时的 REST Web 服务,返回推文列表。

首先,需要添加 Spring Boot WebFlux Starter 依赖:

org.springframework.bootspring-boot-starter-webflux

下面 REST Endpoint,比较耗时:

@GetMapping("/slow-service-tweets")
private List 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"));
}

3.1. RestTemplate 调用耗时服务

接着实现 REST Endpoint,通过 WebClient 调用耗时服务。

先使用 RestTemplate:

@GetMapping("/tweets-blocking")
public List getTweetsBlocking() {log.info("Starting BLOCKING Controller!");
final String uri = getSlowServiceUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity> response = restTemplate.exchange(
uri, HttpMethod.GET, null,new ParameterizedTypeReference>(){});
List 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!

3.2. WebClient 调用耗时服务

接下来用 WebClient 调用耗时服务:

@GetMapping(value = "/tweets-non-blocking",
produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux getTweetsNonBlocking() {log.info("Starting NON-BLOCKING Controller!");
Flux 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 对象。

这次的日志:

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)

请注意:这个 Endpoint 方法在收到响应前就已执行完成。

4. 总结

这篇文章讨论了 Spring 中使用 Web Client 的两种不同方式。

RestTemplate 采用 Java Servlet API,因而是阻塞式同步调用。相反,WebClient 是异步的,等待响应的同时不会阻塞正在执行的线程。只有在响应结果准备就绪时,才会发起通知。

RestTemplate 仍然有用武之地。非阻塞模式在某些场景下比阻塞方法占用系统资源要少得多,这时 WebClient 是一种更好的选择。

本文所有源代码可以在 GitHub 上找到。

github.com/eugenp/tutorials/tree/master/spring-5-reactive-2

推荐阅读

(点击标题可跳转阅读)

神秘的 Eclipse Collections API :  forEachInBoth

Java 新特性实例之自动化测试

如何访问 redis 中的海量数据?避免事故产生

看完本文有收获?请转发分享给更多人

关注「ImportNew」,提升Java技能

4adfb71d94c1aea2eb32bd1d374899cf.png

好文章,我在看❤️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值