WebFlux 是 Spring 5 引入的响应式编程框架,作为传统 Spring MVC 的替代方案,特别适合高并发、低延迟的异步非阻塞场景
WebFlux特别适合微服务架构中的网关、代理服务和高并发API场景,但对于传统CRUD应用,Spring MVC仍然是更简单的选择。
使用过程中的注意点:
- 避免阻塞操作:不要在响应式链中调用阻塞方法
- 合理使用调度器:控制线程模型(Schedulers)
- 背压处理:正确处理订阅者的需求速率
- 错误处理:使用onErrorResume等操作符
核心概念
- 响应式编程模型:基于 Reactive Streams 规范,使用 Publisher-Subscriber 模式
- 非阻塞 I/O:使用 Netty 或 Servlet 3.1+ 容器作为底层服务器
- 函数式编程:支持 Router Functions 和 Handler Functions 的声明式 API
主要组件
1. Reactive 核心类型
Mono: 表示 0 或 1 个元素的异步序列Flux: 表示 0 到 N 个元素的异步序列2. WebFlux 架构
- 基于 Reactor 库实现响应式流
- 支持两种编程模型:
- 注解驱动(类似 Spring MVC)
- 函数式端点(Router Functions
关键特性
- 响应式数据访问:支持 Reactive Repositories (MongoDB, Cassandra, Redis等)
- WebClient:非阻塞的HTTP客户端
- 服务器推送事件(SSE):支持实时数据流
- WebSocket支持:全双工通信
- 函数式路由:RouterFunction API
使用案例
@SpringBootApplication public class WebFluxDemoApplication { public static void main(String[] args) { SpringApplication.run(WebFluxDemoApplication.class, args); } } @RestController @RequestMapping("/api") class DemoController { @GetMapping("/hello") public Mono<String> hello() { return Mono.just("Hello, WebFlux!"); } @GetMapping("/numbers") public Flux<Integer> numbers() { return Flux.range(1, 10) .delayElements(Duration.ofMillis(200)); } }<project> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> </dependencies> </project>WebFlux 通知前端的机制
WebFlux 主要通过以下几种方式将数据推送到前端:
1. HTTP 响应式流 (Server-Sent Events/SSE)
javaCopy Code
@GetMapping("/stream") public Flux<String> streamEvents() { return Flux.interval(Duration.ofSeconds(1)) .map(sequence -> "Event #" + sequence); }
- 特点:单向服务器推送,基于HTTP长连接
- 前端通过EventSource API接收
2. WebSocket 双向通信
javaCopy Code
@GetMapping("/ws") public Mono<Void> handleWebSocket(WebSocketSession session) { return session.send( Flux.interval(Duration.ofSeconds(1)) .map(i -> session.textMessage("Tick #" + i)) ); }
- 特点:全双工通信,低延迟
- 前端通过WebSocket API连接
3. 响应式HTTP请求
javaCopy Code
@GetMapping("/data") public Mono<Data> getData() { return dataService.fetchData(); }
- 特点:传统请求-响应模式但非阻塞
- 前端通过fetch/axios等接收
4. Server Push (HTTP/2)
javaCopy Code
@GetMapping("/push") public Mono<ResponseEntity<String>> pushResource() { return ServerResponse.ok() .header("Link", "</style.css>; rel=preload; as=style") .body(Mono.just("Pushing resources")); }
- 特点:服务器主动推送资源
- 浏览器自动处理
核心原理
- 响应式背压:前端可以控制数据流速
- 非阻塞IO:服务器线程不被阻塞
- 事件驱动:数据就绪时自动触发推送
- 协议支持:兼容HTTP/1.1, HTTP/2, WebSocket等
需要根据具体场景和前端技术栈进行统一选择。以下是选择建议:
-
技术匹配原则:
- SSE需要前端使用EventSource API
- WebSocket需要前端使用WebSocket API
- HTTP Streaming需要前端支持分块传输解析
- 普通响应式请求需要前端适配异步处理
-
场景适配指南:
| 模式 | 前端技术需求 | 适用场景 | 不适用场景 |
|---|---|---|---|
| SSE | EventSource/Fetch API | 单向实时通知(如股票行情) | 需要双向交互的场景 |
| WebSocket | WebSocket API | 聊天室/实时协作/游戏 | 简单数据查询 |
| HTTP Streaming | Fetch+ReadableStream | 大文件下载/实时日志 | 需要精确控制消息边界 |
| 普通响应式请求 | 常规AJAX库(axios等) | CRUD操作/普通API调用 | 高频率实时更新 |
-
统一性要求:
- 同一功能模块应保持通信机制一致
- 混合使用会导致前端代码复杂度剧增
- 需要前后端团队明确协议规范(如WS消息格式)
-
典型组合方案:
textCopy Code
方案1:仪表盘系统 - 主要:SSE推送实时指标 - 辅助:普通HTTP请求获取配置 方案2:在线协作应用 - 核心:WebSocket双向通信 - 附件:HTTP文件分块上传 方案3:日志监控系统 - 主通道:HTTP Streaming传输日志 - 控制面:RESTful API操作
最佳实践是:在项目设计阶段就确定通信矩阵,为每类数据交互明确指定通知机制,并建立对应的前端处理规范。
Mono和Flux函数详解
Mono和Flux是Project Reactor(也是Spring WebFlux的基础)中的两个核心响应式类型,用于表示异步数据流。
Mono 详解
Mono表示0或1个元素的异步序列,类似于Java中的Optional或Future。
主要特性:
- 表示单值或空值的异步计算
- 支持链式操作(类似于Stream API)
- 可以表示成功、错误或空值三种状态
常用创建方法:
javaCopy Code
Mono.just("Hello") // 创建包含单个值的Mono Mono.empty() // 创建空Mono Mono.error(new RuntimeException()) // 创建错误Mono Mono.fromFuture(future) // 从Future创建 Mono.fromCallable(() -> "value") // 从Callable创建
常用操作符:
map(): 转换值flatMap(): 异步转换值filter(): 过滤值doOnNext(): 副作用操作onErrorResume(): 错误恢复zipWith(): 合并两个Mono
Flux 详解
Flux表示0到N个元素的异步序列,类似于Observable或Stream。
主要特性:
- 表示多值异步序列
- 支持背压(backpressure)
- 可以表示成功、错误或完成三种状态
常用创建方法:
Flux.just("A", "B", "C") // 创建包含多个值的Flux Flux.fromIterable(list) // 从集合创建 Flux.range(1, 10) // 创建数字范围 Flux.interval(Duration.ofSeconds(1)) // 定时发射 Flux.fromStream(stream) // 从Stream创建
常用操作符:
map(): 转换每个元素flatMap(): 异步转换每个元素filter(): 过滤元素take(n): 取前n个元素skip(n): 跳过前n个元素reduce(): 聚合操作collectList(): 收集为Listbuffer(): 缓冲多个元素
核心区别
| 特性 | Mono | Flux |
|---|---|---|
| 元素数量 | 0或1个 | 0到N个 |
| 适用场景 | 单个异步结果(如HTTP响应) | 流式数据(如SSE、WebSocket) |
| 完成信号 | 发射元素后立即完成 | 发射所有元素后发送完成信号 |
| 典型操作符 | then, defaultIfEmpty | window, groupBy, sample |
实际应用示例
// 组合多个Mono Mono<String> mono1 = Mono.just("Hello"); Mono<String> mono2 = Mono.just("World"); Mono.zip(mono1, mono2) .map(tuple -> tuple.getT1() + " " + tuple.getT2()) .subscribe(System.out::println); // 处理Flux流 Flux.interval(Duration.ofMillis(100)) .take(5) .map(i -> "Item " + i) .subscribe(System.out::println);
Mono和Flux是响应式编程的基础构建块,理解它们的特性和操作符对于有效使用WebFlux至关重要。
全双工通信 vs 半双工通信详解
核心区别
| 特性 | 全双工通信 (Full-Duplex) | 半双工通信 (Half-Duplex) |
|---|---|---|
| 数据流向 | 双向同时传输 | 双向交替传输 |
| 通道占用 | 同一时间双向占用通道 | 同一时间单向占用通道 |
| 延迟 | 极低(无需等待通道释放) | 较高(需等待对方释放通道) |
| 复杂度 | 较高(需要分离收发通道) | 较低(共享传输通道) |
| 典型协议 | WebSocket, TCP, 电话通话 | HTTP/1.1, 对讲机, RS-485总线 |
技术实现对比
全双工实现原理
graph LR A[客户端] -- 持续发送 --> B[服务器] B -- 同时响应 --> A
- 物理层实现:
- 双绞线(不同线对负责不同方向)
- 光纤(不同波长传输不同方向)
- 无线(MIMO多天线技术)
- 协议层实现:
- WebSocket:建立持久双向通道
- HTTP/2:多路复用实现准全双工
- QUIC:基于UDP的多向数据流
半双工实现原理
mermaidCopy Code
graph TD A[客户端] -- 请求数据 --> B[服务器] B -- 处理请求 --> A A -- 等待 --> B B -- 返回响应 --> A
- 工作机制:
- 请求方获取通道控制权
- 发送数据后释放通道
- 接收方获取通道控制权
- 返回响应后释放通道
- 循环1-4步骤
响应式系统中的应用
WebFlux中的双工模式
| 通信方式 | 双工类型 | 实现机制 |
|---|---|---|
| WebSocket | 全双工 | 持久双向二进制帧传输 |
| HTTP/2 | 准全双工 | 多路复用+流优先级 |
| SSE | 半双工 | 长连接服务端单向推送 |
| HTTP/1.1 | 半双工 | 请求-响应轮询模式 |
性能影响对比
| 场景 | 全双工方案 | 半双工方案 | 差异 |
|---|---|---|---|
| 实时聊天 | 延迟<50ms | 延迟>200ms | 4倍延迟差距 |
| 高频数据采集 | 吞吐量10万+/s | 吞吐量1万/s | 10倍吞吐量差距 |
| 大规模IoT设备 | 连接数10万+ | 连接数5千 | 20倍连接数差距 |
| 资源消耗 | 内存占用较高 | CPU占用较高 | 资源消耗类型不同 |
选型建议
优先选择全双工的场景 ✅
- 强实时交互系统:在线游戏/远程控制
- 双向流式处理:视频会议/协同编辑
- 高频数据交换:金融交易系统/IOT监测
- 长连接服务:即时通讯/实时监控
适合半双工的场景 ⚠️
- 传统请求-响应:RESTful API
- 低频数据推送:新闻订阅/告警通知
- 资源受限设备:嵌入式设备通信
- 简单数据采集:传感器定期上报
混合架构实践
现代高并发系统常采用混合双工模式:
mermaidCopy Code
graph LR A[客户端] -- WebSocket全双工 --> B[实时服务] A -- HTTP/2 准全双工 --> C[API网关] C -- HTTP/1.1 半双工 --> D[传统服务]
最佳实践:
- 核心实时通道用WebSocket(全双工)
- 主要API交互用HTTP/2(准全双工)
- 对接遗留系统用HTTP/1.1(半双工)
- 推送服务用SSE(半双工替代轮询)
理解双工差异是设计高并发系统的关键基础,实际选型需综合考虑协议支持、基础设施、团队技术栈等约束条件。
1700

被折叠的 条评论
为什么被折叠?



