Mono 使用指南:响应式编程的核心概念与实践

文章目录

  • [一、Mono 的核心概念](#一、Mono 的核心概念)
  • [二、Mono 的常见用法](#二、Mono 的常见用法)
  • [三、Mono 的常见应用场景](#三、Mono 的常见应用场景)
  • [四、Mono 与 Flux 的区别](#四、Mono 与 Flux 的区别)
  • 五、总结

Mono 是一个常用的 单一值容器 ,它源于 响应式编程 ,特别是在 ReactiveX (即 RxJava、Project Reactor 等)框架中,常见于 Java、C#、Kotlin 等语言 。

简而言之,Mono 是 0 或 1 个值 的容器,它表示 异步操作的单个结果 。它是 Reactive Streams 的一部分,并且通常用于 异步编程 、并发处理 、流式数据处理。


一、Mono 的核心概念

1. Mono 表示一个异步值

  • Mono 可以表示一个未来的值,它的生命周期是从没有结果到获取结果。
  • 它要么完成并返回一个值,要么失败。
  • 它是 0 或 1 个值 ,如果有多个值或没有值,就不适合使用 Mono,而是用 Flux(0 到 N 个值)处理。

例如:

  • 查询数据库,成功时返回数据,失败时返回错误。

2. Mono 比 Future 更强大

在传统的 Java 编程中,我们通常会使用 Future 来表示一个异步结果,但是 Mono 和 Future 有很大的区别,特别是在 响应式流 和 操作链式组合 方面。


二、Mono 的常见用法

1. 创建一个 Mono

java 复制代码
import reactor.core.publisher.Mono;

public class MonoDemo {
    public static void main(String[] args) {
        // 1. 从一个已知值创建 Mono
        Mono<String> helloMono = Mono.just("Hello, World!");
        
        // 2. 创建一个空的 Mono(无值)
        Mono<String> emptyMono = Mono.empty();
        
        // 3. 创建一个出错的 Mono
        Mono<String> errorMono = Mono.error(new RuntimeException("Something went wrong"));
        
        // 4. 创建一个延迟执行的 Mono
        Mono<String> delayedMono = Mono.fromCallable(() -> {
            Thread.sleep(1000);  // 模拟延迟
            return "Hello, after delay!";
        });
        
        // 5. 打印 Mono 的值(订阅)
        helloMono.subscribe(value -> System.out.println("Mono Value: " + value));
        emptyMono.subscribe(value -> System.out.println("Empty Mono Value: " + value), 
                             error -> System.out.println("Error: " + error.getMessage()));
        errorMono.subscribe(value -> System.out.println("This will not be printed"),
                             error -> System.out.println("Error: " + error.getMessage()));
        delayedMono.subscribe(value -> System.out.println("Delayed Mono Value: " + value));
    }
}
  • Mono.just(T):从一个已知值创建 Mono。

  • Mono.empty():创建一个空的 Mono,表示没有任何结果。

  • Mono.error(Throwable):创建一个带有错误的 Mono,表示执行失败。

  • Mono.fromCallable():创建一个延迟执行的 Mono。


2. 异步执行和 Mono 的延迟

你也可以创建一个 延迟执行的 Mono,比如从文件、数据库或外部 API 获取数据时:

java 复制代码
Mono<String> delayedMono = Mono.fromCallable(() -> {
    Thread.sleep(1000); // 模拟延迟
    return "Hello, after delay!";
});

这个 Mono 会在触发时异步执行(例如在订阅时)。


3. 订阅 Mono 并获取值

java 复制代码
mono.subscribe(value -> {
    System.out.println(value);  // 打印 "Hello, World!"
});

调用 subscribe() 会启动异步流。直到调用 subscribe(),Mono 才会开始执行,其他操作(例如数据库查询、文件读取)也会在这时发生。


4. 处理成功和错误

Mono 可以通过 doOnSuccess 和 doOnError 来处理不同的事件:

java 复制代码
Mono.just("Hello")
    .doOnSuccess(value -> System.out.println("成功获取值:" + value))
    .doOnError(error -> System.err.println("发生错误:" + error.getMessage()))
    .subscribe();

如果 Mono 成功,会执行 doOnSuccess,如果发生错误会执行 doOnError。


5. 错误处理

java 复制代码
Mono<String> result = Mono.just("Some value")
    .map(value -> {
        if (value.equals("Some value")) {
            throw new RuntimeException("Something went wrong!");
        }
        return value;
    })
    .onErrorReturn("Default value");  // 如果发生错误,返回默认值

result.subscribe(value -> System.out.println(value));  // 输出 "Default value"

这里的 onErrorReturn 会在发生异常时返回一个默认值。


6. 链式组合操作

Mono 允许通过链式调用进行流式组合:

java 复制代码
Mono<String> result = Mono.just("Hello")
    .map(String::toUpperCase)   // 转成大写
    .filter(value -> value.startsWith("H"))  // 过滤掉不符合条件的
    .defaultIfEmpty("Default Value");  // 如果为空,返回默认值

result.subscribe(value -> System.out.println(value));  // 输出 "HELLO"
  • map():转换值
  • filter():过滤不符合条件的元素
  • defaultIfEmpty():如果没有值时,使用默认值

7. 等待 Mono 完成并获取结果(阻塞方式)

虽然 Mono 是 异步 的,但是你也可以选择将其 阻塞 以获取最终结果:

java 复制代码
String result = mono.block();  // 会阻塞等待直到值返回
System.out.println(result);  // 输出获取到的值

注意: 阻塞操作一般不推荐在响应式流中使用,因为它违背了响应式编程的非阻塞特性。


三、Mono 的常见应用场景

1. 数据库查询

在响应式框架(如 Spring WebFlux)中,Mono 经常用于从数据库异步查询单一记录或对象。

java 复制代码
public Mono<User> getUserById(String userId) {
    return userRepository.findById(userId);  // 假设这是一个异步查询
}

2. Web 请求响应

在 Spring WebFlux 中,Mono 可以用来表示 HTTP 响应,特别是对于异步请求。

java 复制代码
@GetMapping("/user/{id}")
public Mono<User> getUser(@PathVariable String id) {
    return userService.getUserById(id);  // 返回 Mono<User>,表示异步的用户数据
}

四、Mono 与 Flux 的区别

  • Mono 只表示 0 或 1 个元素,适合用于表示单一值或操作的结果。
  • Flux 表示 0 到 N 个元素,适合处理流式数据或多个值。
java 复制代码
Flux<Integer> flux = Flux.just(1, 2, 3, 4, 5);
Mono<Integer> mono = Mono.just(1);

五、总结

  • Mono 是用于表示 单一值的异步容器 ,是 响应式编程 中常用的工具。
  • 它可以 异步获取 、处理 或 返回一个结果。
  • Mono 和 Flux 都是 Reactive Streams 的实现,帮助我们以更加高效和声明式的方式编写异步代码。
相关推荐
学长毕设2 分钟前
基于springboot的实验室设备管理系统
java·spring boot·后端
学长毕设27 分钟前
基于springboot的社区养老监护系统的设计与实现
java·spring boot·后端
会编程的吕洞宾31 分钟前
RAG检索质量怎么评估?3个指标+LLM裁判实战
java·开发语言·人工智能·后端
卢总霸气34 分钟前
上海交大机动学院学位论文参考文献Zotero CSL 样式-2026
java
段一凡-华北理工大学39 分钟前
高炉能源系统智能化:热风炉、煤气与极致能效~系列文章07:高炉煤气:产生规律与全厂用户平衡
java·前端·能源
咖啡八杯44 分钟前
Redis 工具封装:RedisCache 对 Operations 体系的二次封装
java·数据库·redis·缓存·框架·springboot·若依
wno7041 小时前
Springboot国际化信息(i18n)解析
java·spring boot·后端
eleven_4u1 小时前
QPS如何计算,如何部署架构
java·linux·运维·jvm·中间件
牧瀬クリスだ1 小时前
Redis Hash实战:高效存储对象与购物车
java·数据库·redis·算法·哈希算法
文丑颜不良啊1 小时前
LeetCode1141~1160题目解析
java·leetcode