Spring 5 引入了一个名为 WebClient 的新反应式 Web 客户端。在这篇文章中,我将展示何时以及如何使用 Spring WebClient 与 RestTemplate。我还将描述 WebClient 提供的功能。
RestTemplate是一个central Spring 类,它允许从客户端进行 HTTP 访问。RestTemplate 提供 POST、GET、PUT、DELETE、HEAD 和 OPTIONS HTTP 方法。RestTemplate 的简单用例是使用 Restful Web 服务。
您可以创建一个提供 RestTemplate 实例的 bean。然后,您可以@autowire
在计划调用 REST 服务的任何类中使用此 bean。RestTemplate 是实现接口的类RestOperations
。
以下代码显示了 bean 的声明:
@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 方法来获取评论数据。
基本上,一个人必须做
Spring 5 引入了一个名为 WebClient 的响应式 Web 客户端。它是执行网络请求的接口。它是 Spring Web 反应模块的一部分。WebClient 最终将取代 RestTemplate。
最重要的是,WebClient 是反应式的、非阻塞的、异步的,并且在 HTTP 协议 Http/1.1 上工作。
要使用 WebClient,必须要满足以下条件
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 获取用户列表。
我们已经知道这两个功能之间的一个关键区别。WebClient 是一个非阻塞客户端,而 RestTemplate 是一个阻塞客户端。
RestTemplate 在底层使用 Java Servlet API。Servlet API 是一个同步调用者。因为是同步的,线程会阻塞,直到webclient响应请求。
因此,等待结果的请求将会增加。这将导致内存增加。
另一方面,WebClient 是一个异步非阻塞客户端。它在底层使用 Spring 的反应式框架。WebClient 是 Spring-WebFlux 模块的一部分。
Spring WebFlux 使用反应器库。它提供 Mono 和 Flux API 来处理数据序列。Reactor 是一个反应流库。而且,它的所有运营商都支持非阻塞背压。
我们可以结合 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 的地方。
``` 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 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 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,以及它提供的不同功能。