WebFlux 响应式入门:WebClient 与注解式控制器差异

传统 MVC 是"一个请求占一个线程"阻塞模型,线程常在等待 IO 时闲置。WebFlux 是 Spring 5+ 的响应式 Web 栈:少量事件循环线程支撑海量并发请求,IO 等待时不占线程。Boot 3 中它默认跑在 Netty 上。本章对比它与 MVC 注解式控制器的差异,并给出 WebClient 用法。

引入与取舍

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

不要与 spring-boot-starter-web 同时引入,二者冲突会让自动配置无所适从。什么时候值得用:网关、高并发 IO 密集(大量调用外部 HTTP/缓存);什么时候别硬上:链路里满是阻塞 JDBC、同步第三方 SDK 时,收益有限复杂度翻倍——已有 MVC 服务不必为赶时髦迁移。

注解式控制器:注解一样,返回类型不同

@RestController
@RequestMapping("/api/orders")
public class OrderController {
    private final OrderService orderService;   // 返回响应式类型

    @GetMapping("/{id}")
    public Mono<OrderDto> get(@PathVariable String id) {
        return orderService.findById(id);      // Mono:0 或 1 个结果
    }

    @GetMapping
    public Flux<OrderDto> list() {
        return orderService.findAll();         // Flux:0..N 个结果(流式)
    }
}

与 MVC 的关键差异:

  • 线程模型:MVC 每请求占一条 servlet 线程直到响应结束;WebFlux 请求由 Netty 事件循环驱动,无结果时不占线程;
  • 响应式类型:方法返回 Mono/Flux 而非直接对象,框架负责订阅;操作符 map/flatMap/filter 与 Java Stream 形似,但懒执行 + 背压(消费者慢则上游放慢),"nothing happens until you subscribe";
  • 阻塞即原罪:在响应式管道里调 Thread.sleep、JDBC、阻塞 RestTemplate 会卡死事件循环线程,是性能反模式;
  • 事务/安全上下文:@Transactional 事务绑定线程,@AuthenticationPrincipal 之类依赖 ThreadLocal 的组件在响应式下要改用 Reactive 变体(R2DBC、ReactiveSecurityContext),细节以官方文档为准。

WebClient:非阻塞 HTTP 客户端

WebFlux 项目里替代 RestTemplate 的标配:

WebClient client = WebClient.builder()
        .baseUrl("https://example.com")
        .build();

Mono<UserDto> mono = client.get()
        .uri("/api/users/{id}", 1L)
        .retrieve()                       // 取响应
        .bodyToMono(UserDto.class);       // 反序列化为 Mono

mono.subscribe(u -> System.out.println(u));   // 输出:UserDto(id=1, name=张三)
  • 整条链非阻塞,多个外部调用可用 Mono.zip(...)/Flux.merge(...) 并发聚合,比串行阻塞快得多;
  • 处理错误用 onErrorResume(...) 回退或 .retrieve().bodyToMono(...) 配合自定义状态处理;
  • 在 MVC 工程里 WebClient 也能用(它是独立的响应式客户端),别把 WebClient 与 WebFlux 划等号;
  • 测试用 WebTestClient 发起请求断言,写法与 MockMvc 相近。

选择建议

网关、BFF、实时推送(SSE/WebSocket)、高并发 IO 服务 → WebFlux 收益明显;内部 CRUD、重 DB 逻辑 → MVC 更务实。响应式对团队心智要求高,先想清楚问题再选技术。

小结:WebFlux 以 Mono/Flux + 事件循环换高并发;注解式控制器写法与 MVC 几乎一致,但阻塞调用、ThreadLocal 依赖是红线;HTTP 调用统一用非阻塞的 WebClient。

笔记加载中…