webclient是spring 5.0起官方推荐的非阻塞响应式http客户端,基于reactor实现异步调用,返回mono/flux类型,支持超时、错误恢复与服务发现,配置全局bean后可直接在service中发起异步请求并用mono.zip等操作符编排多个调用。

Spring Boot 中发起微服务异步调用,AsyncRestTemplate 已被废弃,不应再使用;官方自 Spring 5.0 起明确推荐 WebClient 作为现代、非阻塞、响应式的 HTTP 客户端。它天然支持异步、流式、超时控制和错误恢复,是当前微服务间异步通信的首选方案。
下面直接讲清楚怎么用 WebClient 做微服务异步调用,不绕弯、不提过时方案。
WebClient 是怎么做到“异步”的?
WebClient 底层基于 Reactor(Project Reactor),返回的是 Mono<t></t> 或 Flux<t></t> —— 它们是惰性、非阻塞、声明式的响应式类型。
调用 .retrieve().bodyToMono(...) 不会立即发请求,只有当你 .subscribe() 或 .block()(不推荐)或在 WebFlux controller 中返回它时,才真正触发异步执行。
所以,“异步”不是靠多线程池模拟,而是 I/O 层面的事件驱动复用,资源利用率高、吞吐强。
如何配置并注入全局 WebClient Bean
推荐统一配置超时、基础 URL、默认头等,便于维护:
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
// 使用 Reactor Netty 客户端,可设连接/读写超时
HttpClient httpClient = HttpClient.create()
.responseTimeout(Duration.ofSeconds(5))
.doOnConnected(conn -> conn
.addHandlerLast(new ReadTimeoutHandler(5))
.addHandlerLast(new WriteTimeoutHandler(5)));
return WebClient.builder()
.baseUrl("http://order-service") // 微服务注册名或地址
.clientConnector(new ReactorClientHttpConnector(httpClient))
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024)) // 支持大响应体
.build();
}
}
✅ 注意:
baseUrl可填http://order-service(配合服务发现如 Eureka/Nacos)或http://localhost:8081(本地调试)。若用服务发现,需额外引入spring-cloud-starter-loadbalancer并开启@LoadBalanced。
Alibabacloud Sdk Client Initialization For Java下载在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
怎么在 Service 中异步调用另一个微服务?
假设订单服务要异步查用户信息(UserDTO):
@Service
public class OrderService {
private final WebClient webClient;
public OrderService(WebClient webClient) {
this.webClient = webClient;
}
// 返回 Mono<userdto>,代表“一个将异步完成的用户数据”
public Mono<userdto> fetchUserAsync(Long userId) {
return webClient
.get()
.uri("/api/users/{id}", userId)
.retrieve()
.bodyToMono(UserDTO.class)
.onErrorResume(WebClientResponseException.class, ex -> {
log.warn("调用用户服务失败,userId={}", userId, ex);
return Mono.empty(); // 或 fallback 值,如 Mono.just(defaultUser)
});
}
}</userdto></userdto>
调用方无需 Thread.sleep 或手动管理线程,也不用 @Async 注解——WebClient 本身已是异步。
怎么组合多个异步调用(比如查用户 + 查商品)?
用 Reactor 操作符轻松编排:
public Mono<orderdetail> buildOrderDetailAsync(Long orderId, Long userId, Long itemId) {
Mono<userdto> userMono = fetchUserAsync(userId);
Mono<itemdto> itemMono = fetchItemAsync(itemId); // 同理定义
return Mono.zip(userMono, itemMono)
.map(tuple -> {
UserDTO user = tuple.getT1();
ItemDTO item = tuple.getT2();
return new OrderDetail(orderId, user, item);
})
.onErrorResume(ex -> {
log.error("构建订单详情失败", ex);
return Mono.empty();
});
}</itemdto></userdto></orderdetail>
✅ Mono.zip 会并发发起两个请求,等两者都完成才合并结果,比串行快得多。
常见避坑提醒
- ❌ 不要用
.block()在普通@Service方法里强行等结果——这会阻塞线程,失去异步意义; - ✅ 若 Controller 是 Spring MVC(非 WebFlux),想用 WebClient 异步结果,可返回
CompletableFuture:@GetMapping("/order/{id}") public CompletableFuture<orderdetail> getOrder(@PathVariable Long id) { return buildOrderDetailAsync(id, 1001L, 2001L) .toFuture(); // 转为 CompletableFuture }</orderdetail> - ✅ 日志中打印 Mono 对象看不到值?那是正常的——它还没执行。加
.doOnNext(log::info)或.subscribe()才触发; - ✅ 超时不生效?确保
HttpClient.create().responseTimeout(...)和WebClient的timeout()都配对设置(后者针对整个请求生命周期)。
不复杂但容易忽略。











