Spring 5+ 推荐基于响应式的WebClient,不建议再使用RestTemplate
它的底层原理和 Redis 的 IO 多路复用高度相似。都是通过少量线程管理大量连接,通过状态机/回调来处理数据就绪事件,而不是为每个请求分配一个线程
举个例子:
当你的一个Controller中方法返回Mono<User>时,Spring 的处理流程如下:
- 不立即写入:Spring 发现返回值是
Mono对象,它知道数据还没准备好。于是,它不会立刻向 Socket 写入任何 HTTP 响应体,也不会关闭连接。 - 注册回调:Spring 内部会订阅这个
Mono。它相当于对 WebClient 说:“嘿,当用户数据准备好时,请通知我。” - 线程释放:此时,处理该请求的 I/O 线程可以去处理其他请求了(非阻塞),(返回该Mono对象的)函数栈帧弹出。
- 数据到达:
- 当第三方 API 返回数据,WebClient 解析出
User对象。 Mono发出信号(onNext)。- Spring 接收到信号,将
User序列化为 JSON。 - Spring 通过 Netty异步写入Socket,发送给前端。
- 当第三方 API 返回数据,WebClient 解析出
- 完成响应:数据发送完毕后,Spring 关闭 HTTP 连接。
这里Mono对象存储在堆内存中,只要这些对象还被事件循环(EventLoop)引用着,它们就不会被垃圾回收。因此,即使栈帧弹出,堆中的回调逻辑依然存在,等待数据触发。
响应式的设计初衷:用“堆内存中的轻量级对象”换取“昂贵的线程资源”。
存在问题:GC 压力
虽然Mono很轻,但如果并发量极大(如每秒数万请求),会产生大量的短期对象。
现象:Young GC(年轻代垃圾回收)频率变高。
AI生成自用