Spring WebClient vs RestTemplate——比较和特点

2023-10-14 15:59:20 浏览数 (3)

介绍

Spring 5 引入了一个名为 WebClient 的新反应式 Web 客户端。在这篇文章中,我将展示何时以及如何使用 Spring WebClient 与 RestTemplate。我还将描述 WebClient 提供的功能。

什么是 RestTemplate?

RestTemplate是一个central Spring 类,它允许从客户端进行 HTTP 访问。RestTemplate 提供 POST、GET、PUT、DELETE、HEAD 和 OPTIONS HTTP 方法。RestTemplate 的简单用例是使用 Restful Web 服务。

您可以创建一个提供 RestTemplate 实例的 bean。然后,您可以@autowire在计划调用 REST 服务的任何类中使用此 bean。RestTemplate 是实现接口的类RestOperations

以下代码显示了 bean 的声明:

代码语言:javascript复制
    @Bean
    public RestOperations restOperations()
    {
        return new RestTemplate();
    }

以下代码显示了一个 REST 客户端YelpClient调用 Yelp 的 REST API 来获取出租物业评论。

代码语言:javascript复制
   @Autowired
   private final RestOperations restOperations;

   public List getRentalPropertyReviews(String address)
   {
        String url = buildRestUrl(businessId);
        HttpHeaders httpHeaders = new HttpHeaders();
        String apiKey = getApiKey(YELP);
        httpHeaders.add("Authorization","Bearer "   apiKey);
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity entity = new HttpEntity("parameters", httpHeaders);
        ResponseEntity response;

        try
        {
            response = restOperations.exchange(url, HttpMethod.GET,entity, String.class);
        }
        catch(RestClientException e)
        {
            throw new RuntimeException("Unable to retrieve reviews", e);
        }

    }

在上面的代码中,我们通过添加 Yelp 的 REST API 密钥作为授权的一部分来构建 HTTP 标头。我们调用 GET 方法来获取评论数据。

基本上,一个人必须做

  • 自动装配 RestTemplate 对象
  • 使用授权和内容类型构建 HTTP 标头
  • 使用 HttpEntity 包装请求对象
  • 提供 URL、Http 方法和交换方法的返回类型。

什么是WebClient?

Spring 5 引入了一个名为 WebClient 的响应式 Web 客户端。它是执行网络请求的接口。它是 Spring Web 反应模块的一部分。WebClient 最终将取代 RestTemplate。

最重要的是,WebClient 是反应式的、非阻塞的、异步的,并且在 HTTP 协议 Http/1.1 上工作。

要使用 WebClient,必须要满足以下条件

  • 创建 WebClient 的实例
  • 向 REST 端点发出请求
  • 处理响应
代码语言:javascript复制
WebClient webClient = WebClient
       .builder()
       .baseUrl("https://localhost:8443")
       .defaultCookie("cookieKey", "cookieValue")
       .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) 
       .defaultUriVariables(Collections.singletonMap("url", "https://localhost:8443"))
       .build();

上面的代码显示了一种实例化 WebClient 的方法。您还可以通过简单地使用创建一个实例WebClient webClient = WebClient.create();

WebClient 提供了两种方法exchangeretrieve. exchange 方法通常会获取响应以及状态和标头。retrieve 方法直接获取响应体。它更容易使用。

此外,根据您是尝试获取单个对象作为响应还是对象列表,您可以使用monoor flux

代码语言:javascript复制
this.webClient =
                webClientBuilder.baseUrl("http://localhost:8080/v1/betterjavacode/").build();

this.webClient.get()
                .uri("users")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve().bodyToFlux(UserDto.class).collectList();

上面的代码主要用于webClient从 REST API 获取用户列表。

Spring WebClient 与 RestTemplate

我们已经知道这两个功能之间的一个关键区别。WebClient 是一个非阻塞客户端,而 RestTemplate 是一个阻塞客户端。

RestTemplate 在底层使用 Java Servlet API。Servlet API 是一个同步调用者。因为是同步的,线程会阻塞,直到webclient响应请求。

因此,等待结果的请求将会增加。这将导致内存增加。

另一方面,WebClient 是一个异步非阻塞客户端。它在底层使用 Spring 的反应式框架。WebClient 是 Spring-WebFlux 模块的一部分。

Spring WebFlux 使用反应器库。它提供 Mono 和 Flux API 来处理数据序列。Reactor 是一个反应流库。而且,它的所有运营商都支持非阻塞背压。

如何在 Spring Boot 应用程序中使用 WebClient 的示例

我们可以结合 Spring Web MVC 和 Spring WebFlux 的功能。在本节中,我将创建一个示例应用程序。此应用程序将使用 WebFlux 调用 REST API,我们将构建响应以显示包含用户列表的网页。

RestController此示例是一个获取用户列表的 API:

代码语言:javascript复制
package com.betterjavacode.webclientdemo.controllers;

import com.betterjavacode.webclientdemo.dto.UserDto;
import com.betterjavacode.webclientdemo.managers.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("v1/betterjavacode")
public class UserController
{
    @Autowired
    public UserManager userManager;

    @GetMapping(value = "/users")
    public List getUsers()
    {
        return userManager.getAllUsers();
    }
}

Controller使用 WebClient 调用 REST API 的类如下所示:

代码语言:javascript复制
package com.betterjavacode.webclientdemo.controllers;

import com.betterjavacode.webclientdemo.clients.UserClient;
import com.betterjavacode.webclientdemo.dto.UserDto;
import com.betterjavacode.webclientdemo.managers.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

@Controller
public class MainController
{
    @Autowired
    UserClient userClient;

    @GetMapping(value = "/")
    public String home()
    {
        return "home";
    }

    @GetMapping(value = "/users")
    public String getUsers(Model model)
    {
        List users = userClient.getUsers().block();

        model.addAttribute("userslist", users);
        return "users";
    }
}

现在,UserClient 的重要代码段是我们将使用 WebClient 调用 REST API 的地方。

代码语言:javascript复制
package com.betterjavacode.webclientdemo.clients;

import com.betterjavacode.webclientdemo.dto.UserDto;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

@Service
public class UserClient
{

    private WebClient webClient;

    public UserClient(WebClient.Builder webClientBuilder)
    {
        this.webClient =
                webClientBuilder.baseUrl("http://localhost:8080/v1/betterjavacode/").build();
    }

    public Mono<List> getUsers()
    {
        return this.webClient.get()
                .uri("users")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve().bodyToFlux(UserDto.class).collectList();
    }
}

上面的代码显示首先构建 WebClient,然后使用它retrieve从 REST API 响应。retrieve 方法提供了 mono 或 flux 两种选择。由于我们要获取多个用户,因此我们使用的是 flux。

这表明我们可以使用响应式、非阻塞的 WebClient,它是 Spring Web MVC 框架中 WebFlux 的一部分。

Spring WebClient 中还有什么?

Spring WebClient 是Spring WebFlux框架的一部分。这个 API 的主要优点是开发人员不必担心并发或线程。WebClient 负责这个。

WebClient 有一个内置的 HTTP 客户端库支持来执行请求。这包括 Apache HttpComponents、Jetty Reactive HttpClient 或 Reactor Netty。

WebClient.builder()提供以下选项:

uriBuilderFactory– 自定义 uriBuilderFactory 以使用基本 URL defaultHeader– 每个请求的标头 defaultCookie– 每个请求的 Cookie defaultRequest– 自定义每个请求 filter– 每个请求的客户端过滤器 exchangeStrategies– HTTP 消息读取器/写入器自定义 我已经retrieve在上面的代码演示中展示了方法。

WebClient 还提供了一种带有变量的方法,exchange例如exchangeToMono andexchangeToFlux`。

使用attribute(),我们还可以向请求添加属性。

或者,也可以使用 WebClient 进行同步使用。在我上面的 MainController 示例中,我使用它block来获取最终结果。这基本上会阻止并行调用,直到我们得到结果。

WebClient 提供的一项关键功能是retryWhen(). 对于更具弹性的系统,这是一个很棒的功能,您可以在使用 WebClient 时添加它。

代码语言:javascript复制
     webClient
        .get()
        .uri(String.join("", "/users", id))
        .retrieve()
        .bodyToMono(UserDto.class)
        .retryWhen(Retry.fixedDelay(5, Duration.ofMillis(100)))
        .block();

retryWhen将重试类作为参数。

WebClient 还提供错误处理功能。doOnError()允许您处理错误。当单声道以错误结束时触发。onErrorResume()是基于错误的回退。

结论

在这篇文章中,我展示了什么是 Spring WebClient,我们如何使用 Spring WebClient 与 RestTemplate,以及它提供的不同功能。

0 人点赞