网站首页 > 精选教程 正文
在 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-12-06 使用jmeter进行接口性能测试入门
- 2024-12-06 HttpClient使用不当,服务挂了!是时候系统学习一下了
- 2024-12-06 一次完整的HTTP请求与响应涉及了哪些知识?
- 2024-12-06 HTTP 和 RPC 的区别
- 2024-12-06 基础篇-SpringBoot HTTP接口实战
- 2024-12-06 干掉OpenFeign,SpringBoot 3.0 自带的 HTTP 客户端真香!
- 2024-12-06 Springboot -- 用更优雅的方式发HTTP请求(RestTemplate详解)
- 2024-12-06 Feign : 优雅的调用 API
- 2024-12-06 基于Java的开发框架,编写接口通过UI界面完成自动映射成http接口
- 2024-12-06 HTTP是如何使用TCP连接
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)