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

文章目录

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

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

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


一、Mono 的核心概念

1. Mono 表示一个异步值

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

例如:

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

2. MonoFuture 更强大

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


二、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 可以通过 doOnSuccessdoOnError 来处理不同的事件:

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 是用于表示 单一值的异步容器 ,是 响应式编程 中常用的工具。
  • 它可以 异步获取处理返回一个结果
  • MonoFlux 都是 Reactive Streams 的实现,帮助我们以更加高效和声明式的方式编写异步代码。
相关推荐
这里是彪彪9 小时前
Java中的volatile关键字的作用
java·开发语言
独自破碎E9 小时前
【归并】数组中的逆序对
java·数据结构·算法
范什么特西9 小时前
打开idea项目
java
黎雁·泠崖9 小时前
Java入门从零起步:CMD操作+JDK环境搭建+第一个Java程序
java·开发语言
我的golang之路果然有问题9 小时前
python中 unicorn 热重启问题和 debug 的 json
java·服务器·前端·python·json
码农小卡拉10 小时前
深度解析 Spring Boot 启动运行机制
java·spring boot·后端
weixin_4481199410 小时前
如何装docker
java·云原生·eureka
钦拆大仁10 小时前
如何手搓一个Spring Security
java·后端·spring
yaoxin52112310 小时前
288. Java Stream API - 创建随机数的 Stream
java·开发语言