如何从Mono<Object>中获取实体对象?Spring WebClient调用block()报错如何解决
你遇到的报错是因为当前代码运行在WebFlux默认的非阻塞EventLoop线程中,Spring默认禁止在这类线程中调用block()这类阻塞API,避免阻塞事件循环导致服务吞吐量下降甚至崩溃。
场景1:项目为Spring WebFlux反应式技术栈
不要强行将Mono转换为同步返回的User对象,顺着反应式流的编程范式调整代码即可,后续发送数据到其他远程服务的逻辑直接通过操作符串联:
- 调整
findUserById返回值为Mono<User>
public Mono<User> findUserById(String user_id){ return webClientBuilder.build().get().uri("http://localhost:7854/{userId}", user_id) .retrieve() .onStatus(httpStatus -> HttpStatus.NOT_FOUND.equals(httpStatus), clientResponse -> Mono.empty()) .bodyToMono(User.class); }
- 后续调用时用
flatMap串联发送到其他服务的逻辑
// 示例逻辑:获取用户后发送到另一个远程服务 public Mono<Void> processUser(String userId) { return findUserById(userId) .filter(Objects::nonNull) // 过滤404返回的空值,按需调整异常处理逻辑 .flatMap(user -> otherWebClient.post() .uri("目标远程服务接口地址") .bodyValue(user) .retrieve() .bodyToMono(Void.class) ); }
场景2:项目为传统Spring Web Servlet技术栈
如果你只是用WebClient替代RestTemplate做同步HTTP调用,不需要保持反应式特性,可以主动将请求调度到允许阻塞的线程池执行后再调用block():
public User findUserById(String user_id){ return webClientBuilder.build().get().uri("http://localhost:7854/{userId}", user_id) .retrieve() .onStatus(httpStatus -> HttpStatus.NOT_FOUND.equals(httpStatus), clientResponse -> Mono.empty()) .bodyToMono(User.class) // 切换到支持阻塞操作的弹性线程池执行 .subscribeOn(Schedulers.boundedElastic()) .block(); }
注意事项
- WebFlux项目不建议使用场景2的方案,会彻底丧失反应式编程的非阻塞优势,还可能引发线程资源耗尽问题。
- 原代码中直接字符串拼接URI存在注入风险,建议使用WebClient自带的路径参数占位符写法。
- 404返回
Mono.empty()的逻辑需要配套后续空值判断,避免出现空指针异常。
内容的提问来源于stack exchange,提问作者ChaabFI
相关产品推荐
相关产品推荐

