网站首页 > 技术文章 正文
在 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-30 SpringCloud 远程调用为啥要采用HTTP,而不是RPC?
- 2024-09-30 PRA10.3平台API接口调用 api接口调用教程
- 2024-09-30 程序员2022年你不懂RPC远程过程调用,RPC框架的话真的要被淘汰了
- 2024-09-30 Spring Cloud Gateway一次请求调用源码解析
- 2024-09-30 Go教程34:Go微服务间Http+Json调用
- 2024-09-30 接口测试:A13_HttpRunner_hook_01_钩子机制及用例层面的调用
- 2024-09-30 HarmonyOS如何调用http/https接口?
- 2024-09-30 Feign : 优雅的调用 API 调用feign接口
- 2024-09-30 Spring Boot调用http接口的简单方法
- 2024-09-30 远程调用中,rpc到底比http好在哪里
你 发表评论:
欢迎- 10-13教你使用NetworkManager命令行配置网卡IP
- 10-13NETworkManager:功能强大的网络管理与问题排除工具
- 10-13Linux下NetworkManager和network的和平共处
- 10-13「神马课堂」CentOS 7中network服务与NetworkManager服务
- 10-13linux网卡启动的时候,使用 NetworkManager 调度网络服务
- 10-13如何禁用NetworkManager 如何禁用笔记本自带键盘
- 10-13NetworkManager 简介 network manager作用
- 10-13超强大的网络维护管理软件NETworkManager
- 13℃一般人不敢动系列之—基于logback的日志“规范”和“脱敏”
- 13℃MybatisPlus保姆级学习笔记(四)条件构造器Wrapper方法详解
- 12℃Spring Boot 2.5.0 发布:支持Java16、Gradle 7、Datasource调整
- 11℃MybatisPlus介绍以及整合SpringBoot
- 11℃MyBatis-Plus自动填充新增更新时间
- 11℃聊聊:Mybatis-Plus 新增获取自增列id,这一次帮你总结好
- 10℃Web前端培训:Python与JavaScript — 哪一种最适合Web开发
- 9℃「Java工具类」Apache的DigestUtils加密工具类和Base64加解密类
- 0℃未命名
- 最近发表
-
- 教你使用NetworkManager命令行配置网卡IP
- NETworkManager:功能强大的网络管理与问题排除工具
- Linux下NetworkManager和network的和平共处
- 「神马课堂」CentOS 7中network服务与NetworkManager服务
- linux网卡启动的时候,使用 NetworkManager 调度网络服务
- 如何禁用NetworkManager 如何禁用笔记本自带键盘
- NetworkManager 简介 network manager作用
- 超强大的网络维护管理软件NETworkManager
- CTF-Web:xxe+jar协议缓存实现命令执行
- kubernetes的service开启NodePort在宿主机无法找到监听端口?
- 标签列表
-
- mybatis返回int (51)
- jsonproperty注解无效 (52)
- jtextfield (48)
- flaskrequest.data (53)
- preflight请求 (48)
- request.getheader (57)
- pomexclusion (55)
- javassh连接远程服务器 (80)
- java-jar输出日志 (71)
- mybatis.type-aliases-package (63)
- arraystoreexception (56)
- 线程池submit (67)
- sshshell (49)
- vue2props (57)
- 微信小程序form表单提交 (55)
- javabase64转图片 (55)
- javaobject转map (74)
- java接口文档生成工具 (49)
- tcpflags (59)
- 虚拟机共享文件夹在哪 (60)
- shiro设置session过期时间 (61)
- python-msimpleserver (48)
- bufferedreader.readline() (48)
- map转list对象 (50)
- resttemplate文件上传 (57)
本文暂时没有评论,来添加一个吧(●'◡'●)