为了账号安全,请及时绑定邮箱和手机立即绑定

掌握Spring Boot中的WebClient:何时以及为何要选择它而不是RestTemplate

在开发Spring Boot应用程序时,与RESTful网络服务通信是一项常见需求。传统上,开发人员使用RestTemplate来实现这个目标。然而,随着响应式编程和更高效的资源利用需求的出现,WebClient已成为更优选的选择。本文探讨了RestTemplateWebClient之间的差异,并并通过实际例子说明了为什么WebClient更适合当今的应用程序。

特别声明:何时使用RestTemplate?
关于 RestTemplate 的定义:

RestTemplate 是 Spring 框架提供的一个同步且阻塞的客户端,用于消费 RESTful Web 服务。它发送请求并等待响应。尽管简单且被广泛使用,由于其阻塞特性,它不太适合高吞吐量或低延迟的应用场景。

RestTemplate的关键特性:

RESTTemplate 是一个用于简化HTTP请求的工具。以下是它的主要特性:

  • 同步且阻塞。
  • 使用基本的HTTP请求非常简单。
  • 与传统的Spring应用集成得很好。

尽管 WebClient 的流行度日益增长,RestTemplate 仍然在许多 Spring Boot 应用程序中广泛使用,特别是在传统的同步架构中。以下是一些使用 RestTemplate 仍然有效且通常更佳的情况。

1. 同步应用

如果你的应用程序设计为同步阻塞系统,每个操作都会等待前一个操作完成,RestTemplate 就足够简单易用。例如:

  • 未采用反应式或异步模式的遗留系统。
  • 流量小且扩展需求不高的内部工具和系统。
2. 简单用法示例

对于像一次性的HTTP请求、下载小文件或提交数据到服务这样的简单用例,RestTemplate 提供了便捷的使用体验:

  • 快速实现 CRUD 功能。
  • 与现有的 Spring MVC 应用程序集成。
3. 遗留系统

许多较旧的应用程序是在 WebClient 出现之前开发的,并且它们高度依赖于 RestTemplate,因此。将这些应用程序重构以使用 WebClient 可能需要相当大的努力,而短期内好处却不大。

  • 采用单体架构的应用。
  • 没有性能瓶颈的系统,无需使用非阻塞 I/O。
4. 有限的并发需求

在对并发要求不高的应用场合,且资源利用率不是主要考虑因素的情况下,RestTemplate 就足够了。

  • 仅供少数内部员工使用的企业应用程序。
  • 定期进行 HTTP 请求的批处理任务或 ETL 系统。
5. 测试和原型设计

为了快速原型制作或测试API接口,RestTemplate 因其简洁性和低配置门槛而广受欢迎。

为什么RestTemplate技术不被广泛使用?
  1. 历史的重要性
  • RestTemplate 在 Spring 生态系统中很早就被引入,并在响应式编程流行之前成为 Spring 应用程序中进行 HTTP 通信的标准。
  • 长期以来一直是 Spring 中用于消费 REST API 的默认选择,许多开发者都非常熟悉它。

2. 易于使用

  • RestTemplate 简单易用的 API 允许开发人员只需少量配置即可执行常见的 HTTP 操作,如 GETPOSTPUTDELETE 请求。

3. 非常强大的生态系统支援

许多 Spring Boot 教程、指南和示例都使用了 RestTemplate,使得开发者能够获取丰富的资源及社区支持。

4. 同步性

  • 它的阻塞特性与传统的编程方式自然吻合,使得从桌面或单体应用转到 web 服务的开发者更容易上手。

5. 稳重可靠

  • RestTemplate 是一个成熟稳定的库,在许多使用场景中表现可靠,因此是许多用例中的可靠选择。

何时使用WebClient?

WebClient 的定义:

WebClient 是 Spring WebFlux 框架中提供的一种非阻塞、响应式的 web 客户端,主要用于异步和流处理。它适用于异步和流处理,非常适合需要高并发和高可扩展性的应用程序。

WebClient的主要特点
  • 异步且非阻塞。
  • 支持同步和响应式编程模型。
  • 适用于实时流数据处理场景。
  • 内置支持函数式编程。

WebClientSpring WebFlux 模块中引入的一个强大的工具,旨在处理异步、非阻塞的 HTTP 请求。它的灵活性、效率和现代设计使其适用于各种应用场景。以下将详细讨论 WebClient 在推荐使用的情境中的优势。

反应式和无阻塞应用

WebClient 是开发反应式应用时的最佳选择。反应式编程通过利用非阻塞 I/O 设计,可以高效处理大量并发请求。在以下情况使用 WebClient:

  • 反应式 API:如果你的应用使用了 ReactorRxJava 或其他反应式框架,WebClient 可以无缝集成。
  • 事件驱动的架构:依赖事件的系统,如物联网平台,可以充分利用 WebClient 的异步特性。

例子

    public Mono<User> fetchUser(String userId) {  
        return WebClient.create()  
            .get()  
            .uri("https://api.example.com/users/{id}", userId)  
            .retrieve()  
            .bodyToMono(User.class);  
    }
2. 微服务间的通信

在微服务架构里,服务经常需要互相通信。WebClient 能够实现高效且高吞吐量的跨服务通信。它允许:

  • 并发请求:可以同时发送多个请求而不阻塞线程。
  • 低延迟响应:处理实时数据时减少响应时间。

例子

/**

* 根据用户ID获取用户的订单列表

* @param userId 用户ID

* @return 用户的订单Flux流
 */
public Flux<Order> fetchUserOrders(String userId) {  
    return WebClient.create()  
        .get()  
        .uri("https://orderservice.com/orders?userId=" + userId)  
        .retrieve()  
        .bodyToFlux(Order.class);  
}
3. 高并发的要求(即系统能在短时间内处理大量请求)

对于需要处理大量同时请求的应用程序,WebClient 非常合适。

  • 与像 RestTemplate 这样的阻塞客户端相比,它使用的线程更少,因此具有更好的可扩展性。
  • 适用于数千用户或在资源受限环境运行的服务的应用程序。

示例用法

  • 用户数达数百万的社交媒体网站。
  • 在销售活动期间,电商平台需要应对大量并发请求。
4. 实时流数据和实时数据

WebClient 在处理流数据和服务器发送事件(SSE)方面表现出色,适用于:适合需要以下功能的应用程序:

  • 数据流:例如,实时消费股票价格更新或传感器数据。
  • 持久连接:处理 WebSocket 或 SSE,适用于聊天、实时仪表板等应用。

例子

    public Flux<StockPrice> streamStockPrices() {  
        return WebClient.create()  
            .get()  
            .uri("https://api.example.com/stock-prices/stream")  
            .retrieve()  
            .bodyToFlux(StockPrice.class);  
    }
5. 处理大数据量

建议处理上传/下载大文件或流大数据集的应用程序使用WebClient客户端,因为它能高效地利用资源。

  • 由于采用了非阻塞 I/O,内存处理非常高效。
  • 支持流式处理数据块,无需将所有内容一次性加载到内存中。

例子

    public Flux<数据块> 下载文件流() {  
        // 下载大文件,并以数据块的形式返回
        return WebClient.create()  
            .get()  
            .uri("https://api.example.com/largefile")  
            .retrieve()  
            .bodyToFlux(数据块.class);  
    }
6. 把老旧系统现代化

随着系统的演进,传统的同步应用通常会被改造为异步和响应式的系统。在这样的转型过程中,WebClient 非常理想。

  • 与现有的同步 API 无缝配合,同时支持响应式编程模式。
  • 允许系统某些部分采用反应式编程,从而实现部分现代化。
7. 容错性和恢复力

WebClient 与 Resilience4j 等库集成,提供容错和弹性的通信功能:

  • 重试:自动重试失败的请求,让一切更顺畅。
  • 熔断器:使用熔断器来防止连接服务之间的级联故障。
  • 超时:设置超时时间,优雅地处理慢速响应。

例子

    import io.github.resilience4j.circuitbreaker.CircuitBreaker;  
    import reactor.core.publisher.Mono;  

    CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("myService");  

    /**

* 具有弹性的用户获取

* @param userId 用户ID

* @return Mono<User>
     */
    public Mono<User> fetchUserWithResilience(String userId) {  
        return WebClient.create()  
            .get()  
            .uri("https://api.example.com/users/{id}", userId)  
            .retrieve()  
            .bodyToMono(User.class)  
            .transformDeferred(CircuitBreakerOperator.of(circuitBreaker));  
    }
8. 安全和Token管理

WebClient 支持强大的安全通信:

  • OAuth2 集成 : 与 Spring Security 集成,用于处理 OAuth2 令牌管理。
  • 自定义身份验证 : 配置自定义头或令牌,以确保安全通信。

例子

    /**

* 使用令牌获取用户信息

* @param userId 用户ID

* @param token 访问令牌

* @return Mono<User> 一个表示异步操作结果的流对象
     */
    public Mono<User> fetchUserWithToken(String userId, String token) {  
        return WebClient.builder()  
            .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token)  
            .build()  
            .get()  
            .uri("https://api.example.com/users/{id}", userId)  
            .retrieve()  
            .bodyToMono(User.class);  
    }
9. 测试和模拟API接口

WebClient 适用于测试,因为它可以与 WireMock 这样的模拟 Web 服务器集成,

  • 模拟API响应来进行集成测试。
  • 测试故障情况,例如超时或错误码。

例子

    @Test
    // @Test 表示这是一个测试方法
    public void 测试获取用户() {
        // 创建一个新的 WireMockServer 实例
        WireMockServer wireMockServer = new WireMockServer();
        // 启动 WireMockServer
        wireMockServer.start();
        // 配置 WireMockServer 来模拟 GET 请求
        wireMockServer.stubFor(get(urlEqualTo("/users/1"))
            .willReturn(aResponse()
                .withHeader("Content-Type", "application/json")
                .withBody("{\"id\":1,\"name\":\"John Doe\"}")));

        // 使用 wireMockServer 的基础URL 创建一个 WebClient 实例
        WebClient webClient = WebClient.create(wireMockServer.baseUrl());
        // 获取用户信息并转换为 Mono<User> 类型
        Mono<User> user = webClient.get().uri("/users/1").retrieve().bodyToMono(User.class);

        // 创建 StepVerifier 并验证用户信息
        StepVerifier.create(user)
            .expectNextMatches(u -> u.getName().equals("John Doe"))
            .verifyComplete();

        // 停止 WireMockServer
        wireMockServer.stop();
    }
  1. 跨平台整合

WebClient的灵活使它能够与各种平台和协议很好地集成,

  • 消费 REST API、GraphQL 端点或 SOAP 服务,
  • 与云平台(如 AWS、Azure 或谷歌云)通信。
为何在Spring Boot应用程序中使用WebClient而不是RestTemplate?

在开发Spring Boot应用程序时,与RESTful web服务进行通信是一个常见的需求。在过去,开发人员使用RestTemplate来达到这一目标。然而,随着反应式编程的兴起和对更高效资源利用的需求,WebClient已经成为更佳的选择。本文将探讨RestTemplateWebClient之间的不同,并通过实际例子说明为什么WebClient更适合现代应用程序。

为什么选择 WebClient 而不是 RestTemplate?(WebClient vs RestTemplate)

  1. 非阻塞I/O:WebClient使用非阻塞模型,这意味着线程在等待响应时不会被阻塞。这在同时进行多次API调用时特别有用。
  2. 支持反应式流:WebClient可以与Reactor和RxJava等反应式库无缝集成,使其适合现代的反应式架构。
  3. 更好的可扩展性:非阻塞行为使WebClient可以同时处理更多的请求,而不会耗尽服务器线程。
  4. 现代且可扩展:WebClient更为灵活且功能更强大,支持诸如大文件流式传输、WebSocket连接处理及多部分请求等高级用例。
比较 RestTemplate 和 WebClient 的实时示例:对比这两个工具
例子 1:从外部API拉取数据

使用 RestTemplate 如下

    import org.springframework.web.client.RestTemplate;  

    public class RestTemplate示例 {  
        private RestTemplate restTemplate = new RestTemplate();  

        /**

* 获取用户详情,传入用户ID
         */
        public String getUserDetails(String userId) {  
            String url = "https://api.example.com/users/" + userId;  
            return restTemplate.getForObject(url, String.class);  
        }  
    }

使用 WebClient:
此处可以添加对WebClient用法的简要说明。

    import org.springframework.web.reactive.function.client.WebClient;  
    import reactor.core.publisher.Mono;  

    public class WebClientExample {  
        private WebClient webClient = WebClient.create();  

        public Mono<String> getUserDetails(String userId) {  
            String url = "https://api.example.com/users/" + userId;  
            return webClient.get()  
                            .uri(url)  
                            .retrieve()  
                            .bodyToMono(String.class);  
        }  
    }

主要的不同点:

  • RestTemplate 会一直等待直到 API 调用结束。
  • WebClient 返回一个 Mono 对象,允许应用程序在等待响应的同时处理其他任务。
示例2:并发的API调用

使用RestTemplate(在多线程环境中效率较低):

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  

public class RestTemplateConcurrentExample {  
    private RestTemplate restTemplate = new RestTemplate();  

    public void 获取多个用户(String[] userIds) {  
        ExecutorService executor = Executors.newFixedThreadPool(userIds.length);  
        for (String userId : userIds) {  
            executor.submit(() -> {  
                String url = "https://api.example.com/users/" + userId;  
                String response = restTemplate.getForObject(url, String.class);  
                System.out.println(response);  
            });  
        }  
        executor.shutdown();  
    }  
}

// 此代码示例展示了如何使用RestTemplate并行获取多个用户信息。

使用 WebClient(简洁高效)

import reactor.core.publisher.Flux;  

public class WebClientConcurrentExample {  
    private WebClient webClient = WebClient.create();  

    public Flux<String> fetchMultipleUsers(String[] userIds) {  
        // 从多个用户ID中获取用户信息
        return Flux.fromArray(userIds)  
                   .flatMap(userId -> webClient.get()  
                                               .uri("https://api.example.com/users/" + userId)  
                                               .retrieve()  
                                               .bodyToMono(String.class));  
    }  
}

主要差别

  • RestTemplate 需要手动管理线程,增加了复杂性。
  • WebClient 自动处理并发,减少了冗余代码。
如何从RestTemplate迁移到WebClient的迁移

将项目中的 RestTemplate 替换成 WebClient:

添加这个依赖。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>

2. 用响应式的等价物替换同步调用。

  1. 更新测试代码以处理如 MonoFlux 等响应式数据流,
结论部分:

WebClient 是一个强大、灵活且现代的 HTTP 客户端,适用于 Spring Boot 应用程序,使开发人员能够构建高效、响应式和可伸缩的系统。它最适合高并发环境、实时数据处理、微服务和现代响应式应用。对于今天启动的新项目或正在迁移至响应式架构的项目,WebClient 显然是最佳选择。

虽然 RestTemplate 更简单,可能更适合小型应用或遗留系统,但 WebClient 是现代的、可扩展的和响应式的 Spring Boot 应用程序的首选。它提供了一种更高效的方式来与 Web 服务交互,特别是在需要高并发和低延迟的场景下。

开发人员可以通过使用WebClient,为应用程序的未来做好准备,并充分发挥反应式编程的潜力。

  • 在促销活动期间处理很多用户同时下单的电商平台。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消