网站首页 > 技术文章 正文
在 web 应用中,通过 HTTP 调用其他服务的 API 是很常见的操作,所以,我们的 web 应用中常常离不开网络客户端工具。
既然涉及到网络请求,就一定会有阻塞和非阻塞的选择问题。
RestTemplate
Spring 框架本身提供了 RestTemplate 作为 web 客户端抽象。在实现上,RestTemplate 使用了 Java Servlet API,该 AP I基于线程-请求模型。这意味着线程将阻塞,直到 web客户端收到响应为止。阻塞代码的问题是每个线程都会消耗了一定数量的内存和CPU周期。
如果有很多传入的请求,又有一些慢速服务,等待结果的请求迟早会堆积起来。因此,应用程序将创建许多线程,这将耗尽线程池或占用所有可用内存。由于频繁的CPU上下文切换,整个应用的性能就会下降。
WebClient
相对的,WebClient 使用 Spring Reactive 框架提供异步、无阻塞的解决方案。
RestTemplate 为每个 HTTP 调用使用线程,而 WebClient 则为每个事件创建类似于“任务”的东西。在实现中,Reactive 框架将对这些“任务”进行排队,并仅在有适当响应时执行它们。
Reactive 框架使用事件驱动的体系结构。它提供了通过响应流 API 组合异步逻辑的方法。因此,与同步阻塞的方法相比,响应式方法可以处理更多的逻辑,同时使用更少的线程和系统资源。
WebClien t是 Spring WebFlux 库的一部分。因此,我们还可以使用响应式 API 编写客户端代码,并使用响应式类型 Mono 和 Flux。
对比
我们使用代码对比一下二者的差异,先看下使用 RestTemplate:
@GetMapping("/blocking")
public List<User> getUserBlocking() {
log.info("Starting BLOCKING Controller!");
final String uri = getSlowServiceUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<List<User>> response = restTemplate.exchange(
uri, HttpMethod.GET, null,
new ParameterizedTypeReference<List<User>>(){});
List<User> result = response.getBody();
result.forEach(user -> log.info(user.toString()));
log.info("Exiting BLOCKING Controller!");
return result;
}
再看一下使用 Sping WebFlux 里的 WebClient:
@GetMapping(value = "/non-blocking",
produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<User> getUserNonBlocking() {
log.info("Starting NON-BLOCKING Controller!");
Flux<User> userFlux = WebClient.create()
.get()
.uri(getSlowServiceUri())
.retrieve()
.bodyToFlux(User.class);
userFlux.subscribe(user -> log.info(user.toString()));
log.info("Exiting NON-BLOCKING Controller!");
return tweetFlux;
}
可以明显看到,RestTemplate 的使用中,代码是完全阻塞等待响应具体的 List<User>,而 WebClient 则是返回了 Flux<User>。Flux 在响应式框架中代表 1 到多个数据,所以它在异步响应成功后,实际也是获得 Iterable<User>。
小结
通过以上介绍,我们知道 RestTemplate 使用 Java Servlet API,因此是同步和阻塞的。
而 Spring WebFlux 里的 WebClient 是异步的,在等待响应返回时不会阻塞正在执行的线程。只有当响应准备就绪时,才会生成结果通知。
RestTemplate 是一个很常规的使用选择,但在某些情况下,与阻塞方法相比,非阻塞方法使用的系统资源要少得多,这个时候 WebClient 会是一个更好的选择。
猜你喜欢
- 2024-09-08 精讲RestTemplate第7篇-自定义请求失败异常处理
- 2024-09-08 java实现调用http请求的几种常见方式
- 2024-09-08 深度原理学习——白话TCP与HTTP的keep–alive机制
- 2024-09-08 有了WebClient还在用RestTemplate?
- 2024-09-08 Spring Boot外部接口调用:使用RestTemplate与WebClient操控HTTP
- 2024-09-08 Java服务优雅上下线(java项目如何上线)
- 2024-09-08 微服务中如何使用RestTemplate优雅调用API(详细分析)
- 2024-09-08 真不是吹,Spring 里这款牛逼的网络工具库你可能没用过
- 2024-09-08 Java工具类封装微服务间HTTP通信(java md5工具类)
- 2024-09-08 5月29号软件资讯更新合集(软件九月)
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)