在 java 响应式编程(reactive programming)中,mono 是 project reactor 库的核心类型之一。它不是 java 标准库(jdk)中的接口,而是 reactor core 提供的响应式类型,常与 spring webflux、r2dbc 等响应式框架一起使用。
mono 的设计灵感来源于 reactive streams 规范,专门用于处理 0 或 1 个元素 的异步数据流。
1. mono 是什么?(核心定义)
- mono 是一个 publisher(reactive streams 中的发布者接口)。
- 它代表一个异步序列,该序列最多发出一个元素(onnext),然后以 oncomplete(完成)或 onerror(错误)信号终止。
- 可以发出:
- 0 个元素(空结果,直接完成)
- 1 个元素(单个值)
- 永远不会发出多个元素(与 flux 区别)
一句话比喻:
- mono ≈ java 中的 optional + completablefuture(异步 + 0/1 值)
- flux ≈ java 中的 stream 或 list(0 到 n 个元素)
官方文档定义(reactor 3.x):
a reactive streams publisher with basic rx operators that emits at most one item via the onnext signal then terminates with the oncomplete signal.
2. mono 与 flux 的区别(面试高频)
| 维度 | mono | flux |
|---|---|---|
| 元素数量 | 0 或 1 | 0 到 n(可无限) |
| 适用场景 | 单个结果(如查询一条记录、http 返回单个对象) | 多个结果(如查询列表、实时数据流) |
| 类比 java 类型 | optional / completablefuture | stream / list / collection |
| 常用操作符 | map、flatmap、then、zipwith、switchifempty | map、flatmap、filter、take、merge、zip |
| 返回类型 | 通常返回 mono | 通常返回 flux |
| 背压支持 | 支持(reactive streams 标准) | 支持 |
什么时候用 mono?
- 数据库单条查询(findbyid)
- http 接口返回单个对象
- 异步计算单个结果(如远程调用、文件读取单值)
- 组合多个异步操作的最终结果
3. mono 的创建方式(常用工厂方法)
import reactor.core.publisher.mono;
import java.time.duration;
// 1. 创建有值的 mono
mono<string> mono1 = mono.just("hello, reactor!");
// 2. 创建空 mono
mono<string> monoempty = mono.empty();
// 3. 从 supplier 创建(延迟执行)
mono<string> monosupplier = mono.fromsupplier(() -> "延迟计算的值");
// 4. 从 callable / runnable 创建
mono<string> monocallable = mono.fromcallable(() -> "从 callable 返回");
// 5. 延迟创建(延迟指定时间)
mono<string> delayed = mono.delay(duration.ofseconds(2))
.map(tick -> "延迟2秒后返回");
// 6. 从 completablefuture 转换
mono<string> fromfuture = mono.fromfuture(completablefuture.supplyasync(() -> "从 future 来"));
// 7. 错误 mono
mono<object> errormono = mono.error(new runtimeexception("出错了!"));4. mono 的核心操作符(operators)
mono 支持大量函数式操作符,实现声明式编程:
mono<user> usermono = userrepository.findbyid(1l) // 返回 mono<user>
.map(user -> user.getname().touppercase()) // 转换
.filter(name -> name.length() > 5) // 过滤(结果仍为 mono)
.flatmap(name -> fetchdetail(name)) // 扁平化嵌套 mono
.switchifempty(mono.just("默认用户")) // 为空时替换
.doonsuccess(user -> system.out.println("成功: " + user))
.doonerror(err -> system.err.println("错误: " + err))
.subscribe(); // 触发执行
常用操作符分类:
- 转换:map、flatmap
- 组合:zipwith、then、and
- 条件:switchifempty、defaultifempty
- 副作用:doonnext、doonerror、doonsubscribe
- 终止:then()(忽略值,返回新 mono)
5. 订阅(subscribe)与执行
mono 是懒执行(lazy)的,只有调用 subscribe() 才会真正开始执行:
mono<string> mono = mono.just("测试");
// 方式1:简单订阅
mono.subscribe(system.out::println);
// 方式2:完整处理 onnext / onerror / oncomplete
mono.subscribe(
value -> system.out.println("收到: " + value),
error -> system.err.println("错误: " + error),
() -> system.out.println("完成!")
);在 spring webflux 中,controller 方法直接返回 mono<t> 或 flux<t>,框架会自动订阅。
6. 实际应用场景(spring webflux 示例)
@restcontroller
@requestmapping("/users")
public class usercontroller {
@getmapping("/{id}")
public mono<user> getuser(@pathvariable long id) {
return userservice.findbyid(id) // 返回 mono<user>
.switchifempty(mono.error(new notfoundexception("用户不存在")));
}
@postmapping
public mono<user> createuser(@requestbody user user) {
return userservice.save(user);
}
}
7. 与其他异步类型的转换
- mono.fromfuture(completablefuture)
- mono.fromcallable(...)
- flux.fromiterable(list).single() → 转 mono(期望单个元素)
- mono.as(flux::from) 或 flux.single()
8. 注意事项 & 最佳实践
- 不要阻塞:mono 内部操作应保持非阻塞(避免 block(),除非测试)。
- 错误处理:优先使用 onerrorreturn、onerrorresume 而不是 try-catch。
- 背压:mono 天然支持背压(下游控制上游速率)。
- 线程模型:默认在当前线程,常用 subscribeon / publishon 切换调度器(schedulers)。
- 测试:用 stepverifier(reactor test)测试 mono/flux。
- 性能:响应式编程适合高并发 io 场景,不适合纯 cpu 密集型计算。
mono vs completablefuture:
- mono:更丰富的操作符 + 声明式 + 支持背压 + 可取消。
- completablefuture:更简单,但功能较少。
总结:
mono 是 reactor 中处理单个异步结果的利器,它让异步编程变得声明式、组合式、可读性强。掌握 mono + flux 后,你就能轻松驾驭 spring webflux、响应式微服务等现代 java 技术栈。
到此这篇关于带你了解java中的mono接口的文章就介绍到这了,更多相关java mono接口内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论