我的 Spring Boot 应用程序使用
WebClient
来调用远程 API。我确实很难理解以下模式之间关于如何使用 WebClient
的区别。
选项 1 - 使用 block()
// WebClient
public Boolean updateUser(long id) {
return webClient.post()
.uri(uriBuilder -> uriBuilder.path(USER_PATH).build(id))
.body(Mono.just(payload), User.class)
.exchangeToMono(clientResponse -> Mono.just(clientResponse.statusCode().is2xxSuccessful()))
.block();
}
// Caller
Boolean result = updateUser(5);
选项 2 - 使用 toFuture():
// WebClient
public CompletableFuture<Boolean> updateUser(long id) {
return webClient.post()
.uri(uriBuilder -> uriBuilder.path(USER_PATH).build(id))
.body(Mono.just(payload), User.class)
.exchangeToMono(clientResponse -> Mono.just(clientResponse.statusCode().is2xxSuccessful()))
.toFuture();
}
// Caller
CompletableFuture<Boolean> future = updateUser(5);
Boolean result = future.get();
据我了解,当
.block()
发出请求并等待响应时,使用 WebClient
会阻塞线程。
当使用
toFuture()
时,WebClient
在不同的线程上运行,因此它不会阻塞。但是使用 .get()
上的 CompletableFuture
方法无论如何都不会阻塞线程吗?
我什么时候会选择其中之一?
在第二个选项中,您允许呼叫者决定何时等待,这看起来比第一个选项更灵活。
TL;博士
Mono.toFuture()
不阻塞,但 Mono.toFuture().get()
阻塞。 block()
在技术上与 toFuture().get()
相同,并且都是阻塞的。
Mono.toFuture()
只是通过订阅并立即解决将 Mono
转换为 CompletableFuture
。但这并不意味着您可以在此之后访问相应Mono
的结果。 CompletableFuture
仍然是异步的,您可以使用 thenApply()
、thenCompose()
、thenCombine()
、... 等方法继续异步处理。 toFuture().get()
是阻塞操作。
CompletableFuture<Double> result = getUserDetail(userId)
.toFuture()
.thenCompose(user -> getCreditRating(user));
其中
getUserDetail
定义为
Mono<User> getUserDetail(String userId);
当您需要组合不同的异步 API 时,Mono.toFuture
非常有用。例如,AWS Java v2 API 是异步的,但基于 CompletableFuture
,但我们可以使用 Mono.toFuture
或 Mono.fromFuture
组合 API。
toFuture 在调试方面效果更好。因为线程调度程序的详细信息。 在调试模式下,当我使用 .block() 方法时抛出此异常:
java.lang.IllegalStateException:block()/blockFirst()/blockLast() 正在阻塞,线程reactor-http-nio-3 不支持