介绍
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 来获取出租物业评论。
@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 端点发出请求
- 处理响应
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 提供了两种方法exchange
和retrieve
. exchange 方法通常会获取响应以及状态和标头。retrieve 方法直接获取响应体。它更容易使用。
此外,根据您是尝试获取单个对象作为响应还是对象列表,您可以使用mono
or flux
。
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:
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 的类如下所示:
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 and
exchangeToFlux`。
使用attribute()
,我们还可以向请求添加属性。
或者,也可以使用 WebClient 进行同步使用。在我上面的 MainController 示例中,我使用它block
来获取最终结果。这基本上会阻止并行调用,直到我们得到结果。
WebClient 提供的一项关键功能是retryWhen()
. 对于更具弹性的系统,这是一个很棒的功能,您可以在使用 WebClient 时添加它。
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,以及它提供的不同功能。