一、核心概念与区别
1. Mono(单数流)
-
定义:表示可能包含 0个或1个 元素的异步序列
-
特点:
-
类似 Java 的
Optional或Future -
发出一个元素后立即发出完成信号
-
适合单值异步操作
-
-
典型场景:
-
单个 HTTP 请求响应
-
数据库查询单个记录
-
返回单一计算结果
-
2. Flux(复数流)
-
定义:表示可能包含 0到N个 元素的异步序列
-
特点:
-
类似 Java 的
Stream或集合 -
可以发出多个元素后完成
-
支持背压(backpressure)
-
-
典型场景:
-
流式数据处理
-
数据库查询多条记录
-
实时事件流(如SSE)
-
二、核心操作符详解
通用操作符(Mono 和 Flux 都支持)
1. 创建操作
// 从值创建
Mono.just("Hello")
Flux.just("A", "B", "C")
// 从集合创建
Flux.fromIterable(Arrays.asList(1, 2, 3))
// 延迟创建
Mono.fromCallable(() -> expensiveOperation())
Flux.fromStream(Stream.generate(() -> random.nextInt()))
2. 转换操作
// map - 同步转换
Mono.just(5).map(x -> x * 2) // Mono(10)
Flux.range(1,3).map(x -> x+1) // Flux(2,3,4)
// flatMap - 异步转换(1→N)
Mono.just(1).flatMap(x -> Mono.just(x * 2)) // Mono(2)
Flux.just(1,2).flatMap(x -> Flux.range(1,x)) // Flux(1,1,2)
3. 过滤操作
// filter
Flux.range(1,10).filter(x -> x%2==0) // 2,4,6,8,10
// take/drop
Flux.range(1,10).take(3) // 1,2,3
Flux.range(1,10).drop(7) // 8,9,10
Mono 特有操作符
1. 默认值处理
// defaultIfEmpty
Mono.empty().defaultIfEmpty("default") // Mono("default")
// switchIfEmpty
Mono.empty().switchIfEmpty(Mono.just("fallback"))
2. 单值特殊处理
// then - 忽略值继续执行
Mono.just(1).then(Mono.just("done")) // Mono("done")
// thenReturn - 忽略值返回指定值
Mono.just(1).thenReturn("completed") // Mono("completed")
Flux 特有操作符
1. 流控制
// buffer - 缓冲
Flux.range(1,5).buffer(2) // [1,2], [3,4], [5]
// window - 窗口化
Flux.range(1,5).window(2) // Flux(1,2), Flux(3,4), Flux(5)
2. 背压处理
// onBackpressureBuffer
Flux.range(1,1000).onBackpressureBuffer(50)
// onBackpressureDrop
Flux.range(1,1000).onBackpressureDrop()
3. 组合操作
// zipWith - 一对一组合
Flux.just("A","B").zipWith(Flux.just(1,2))
// 输出: ("A",1), ("B",2)
// mergeWith - 合并流
Flux.just(1,2).mergeWith(Flux.just(3,4)) // 1,2,3,4
三、实用代码示例
案例1:WebFlux 控制器
@GetMapping("/user/{id}")
public Mono<User> getUser(@PathVariable String id) {
return userRepository.findById(id)
.switchIfEmpty(Mono.error(new UserNotFoundException()));
}
@GetMapping("/orders")
public Flux<Order> getOrders() {
return orderRepository.findAll()
.filter(o -> o.getStatus() == Status.COMPLETED)
.take(100);
}
案例2:响应式数据处理
Flux.fromIterable(dataList)
.window(Duration.ofSeconds(1)) // 每秒一个窗口
.flatMap(window ->
window.groupBy(Data::getCategory)
.flatMap(group ->
group.reduce(new Stats(), Stats::accumulate)
)
)
.subscribe(stats -> storeStats(stats));
案例3:错误处理
Mono.just(userInput)
.map(Integer::parseInt)
.onErrorResume(e -> {
log.warn("Invalid input", e);
return Mono.just(0);
})
.flatMap(number -> calculate(number))
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1)));
四、选择建议
-
使用 Mono 当:
-
操作最多产生一个结果
-
需要表示可能不存在的值
-
执行不返回值的异步操作(
Mono<Void>)
-
-
使用 Flux 当:
-
操作可能产生多个结果
-
处理数据流或集合
-
需要支持背压的流式处理
-
五、性能考虑
-
Mono 更轻量:适合简单场景,开销更小
-
Flux 更强大:适合流式处理但消耗更多资源
-
转换成本:
collectList()(Flux→Mono)和flatMapMany(Mono→Flux)都有开销
通过合理选择 Mono 和 Flux,并正确使用它们的操作符,可以构建高效、可读性强的响应式应用。
1706

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



