mono_1

以下是一个 **完整的综合示例**,展示如何使用 `Mono.zip` 实现 **非阻塞并行调用**,并结合 **超时控制、异常处理、多个 `flatMap` 链式操作** 等场景。示例基于 Spring WebFlux(Reactor 3.x)。

 

---

 

### **场景描述**

1. **并行调用**:同时获取用户基本信息、订单列表和积分(互不依赖)。

2. **超时控制**:订单查询超过 500ms 自动降级。

3. **异常处理**:积分服务失败时返回默认值。

4. **结果聚合**:将所有数据组合为 `UserProfile` 对象。

5. **非阻塞线程**:确保所有操作在弹性线程池执行,不阻塞主线程(如 Netty 事件循环)。

 

---

 

### **完整代码**

```java

import reactor.core.publisher.Mono;

import reactor.core.scheduler.Schedulers;

import java.time.Duration;

import java.util.Collections;

 

// 模拟的实体类

record User(String id, String name) {}

record Order(String id, String product) {}

record Credit(Integer points) {}

record UserProfile(User user, List<Order> orders, Credit credit) {}

 

public class MonoZipComplexExample {

 

    // 模拟远程服务调用(非阻塞)

    private Mono<User> getUserById(String userId) {

        return Mono.fromCallable(() -> {

            Thread.sleep(100); // 模拟延迟

            return new User(userId, "Alice");

        }).subscribeOn(Schedulers.boundedElastic()); // 切换到弹性线程池

    }

 

    private Mono<List<Order>> getOrdersByUser(String userId) {

        return Mono.fromCallable(() -> {

            Thread.sleep(600); // 模拟超时(实际 600ms > 500ms 超时阈值)

            return List.of(new Order("order1", "Laptop"), new Order("order2", "Phone"));

        })

        .subscribeOn(Schedulers.boundedElastic())

        .timeout(Duration.ofMillis(500)) // 超时控制

        .onErrorResume(e -> Mono.just(Collections.emptyList())); // 超时后降级

    }

 

    private Mono<Credit> getCreditByUser(String userId) {

        return Mono.<Credit>fromCallable(() -> {

            if (userId.equals("user1")) {

                throw new RuntimeException("Credit service failed!");

            }

            return new Credit(100);

        })

        .subscribeOn(Schedulers.boundedElastic())

        .onErrorResume(e -> Mono.just(new Credit(0))); // 异常时返回默认值

    }

 

    // 综合调用

    public Mono<UserProfile> getUserProfile(String userId) {

        // 并行获取数据

        Mono<User> userMono = getUserById(userId).cache(); // cache() 避免重复订阅

        Mono<List<Order>> ordersMono = getOrdersByUser(userId);

        Mono<Credit> creditMono = getCreditByUser(userId);

 

        // 使用 zip 并行合并结果

        return Mono.zip(userMono, ordersMono, creditMono)

                .flatMap(tuple -> {

                    User user = tuple.getT1();

                    List<Order> orders = tuple.getT2();

                    Credit credit = tuple.getT3();

                    

                    // 模拟后续异步处理(例如写入日志)

                    return logProfileAsync(user, orders, credit)

                            .thenReturn(new UserProfile(user, orders, credit));

                })

                .doOnNext(profile -> System.out.println("Profile loaded: " + profile))

                .doOnError(e -> System.err.println("Failed: " + e.getMessage()));

    }

 

    private Mono<Void> logProfileAsync(User user, List<Order> orders, Credit credit) {

        return Mono.fromRunnable(() -> {

            System.out.println("Logging to DB: " + user.name());

        }).subscribeOn(Schedulers.boundedElastic()).then();

    }

 

    // 测试

    public static void main(String[] args) {

        MonoZipComplexExample example = new MonoZipComplexExample();

        example.getUserProfile("user1")

                .subscribe(

                        profile -> System.out.println("Final Result: " + profile),

                        error -> System.out.println("Final Error: " + error)

                );

 

        // 防止主线程退出(实际在 WebFlux 中不需要)

        try { Thread.sleep(2000); } catch (InterruptedException e) {}

    }

}

```

 

---

 

### **关键点解析**

1. **非阻塞线程控制**  

   - 所有阻塞操作(如 `Thread.sleep`、网络调用)通过 `subscribeOn(Schedulers.boundedElastic())` 切换到弹性线程池执行,避免阻塞 Reactor 主线程。

 

2. **超时与降级**  

   - `getOrdersByUser` 设置 `timeout(Duration.ofMillis(500))`,超时后通过 `onErrorResume` 返回空列表。

 

3. **异常处理**  

   - `getCreditByUser` 模拟服务失败时,通过 `onErrorResume` 返回默认值 `new Credit(0)`。

 

4. **并行合并**  

   - `Mono.zip(userMono, ordersMono, creditMono)` 并行执行三个 `Mono`,所有结果就绪后触发 `flatMap`。

 

5. **链式操作**  

   - `flatMap` 内调用 `logProfileAsync` 展示异步链式操作,最后返回组合结果 `UserProfile`。

 

6. **日志与监控**  

   - `doOnNext` 和 `doOnError` 用于记录成功/失败日志。

 

---

 

### **输出结果**

根据代码中的延迟和异常模拟,可能的输出:

```text

Logging to DB: Alice

Profile loaded: UserProfile[user=User[id=user1, name=Alice], orders=[], credit=Credit[points=0]]

Final Result: UserProfile[user=User[id=user1, name=Alice], orders=[], credit=Credit[points=0]]

```

 

---

 

### **总结**

- **`Mono.zip`**:用于并行合并多个异步任务,提升性能。

- **超时/降级**:通过 `timeout` + `onErrorResume` 保证系统弹性。

- **非阻塞**:始终通过 `subscribeOn` 隔离阻塞操作。

- **链式扩展**:结合 `flatMap` 实现复杂异步流程。

 

此示例可直接用于 Spring WebFlux 项目或独立的 Reactor 应用中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值