WebFlux_个人学习Subscriber总结
### 文章目录
- [WebFlux_个人学习Subscriber总结](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [@toc](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [1-疑问总结](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [1-👩🏻🦰WebFlux角色扮演](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [2-✅ 数据会广播给所有订阅者](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [3-❌ 错误做法:同一个工人实例订阅多次](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [4-✅ 执行流程是并行的](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [5-👍🏻消费能力推荐](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [2-动手实操](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [1-Publisher 和 Subscriber示例](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [2-Publisher 和 多个Subscriber示例](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [3-难度升级-成功/失败记录](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [3-问题详解](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [1-subscription.request(n)执行解读](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [一、用工厂视角理解整个流程](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [1-角色映射](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [2-完整流程](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [二、关于 request(n) 的关系和含义](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [1-两个 request 之间的关系](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [2-request(3) 中 3 的含义](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [3-两个数值必须相同吗?](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [4-不同数值组合的效果演示](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [三、你代码中的执行流程时序图](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [四、关键要点总结](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [2-Publisher 和 多个Subscriber示例](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [一、同一个Publisher支持多个Subscriber](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [二、多订阅者的核心特性](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [1. **每个Worker独立维护自己的需求计数器**](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [2. **数据会广播给所有订阅者**](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [3. **执行流程是并行的**](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [三、特殊场景:同一个Subscriber多次订阅](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [四、实际应用场景](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [场景1:日志监控系统](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [场景2:数据分发系统](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [五、重要注意事项](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [1. **背压独立**](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [2. **异常隔离**](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [3. **性能影响**](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [4. **线程安全**](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [六、扩展:Processor(中间加工者)](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)
- [总结](#文章目录 WebFlux_个人学习Subscriber总结 @[toc] 1-疑问总结 1-👩🏻🦰WebFlux角色扮演 2-✅ 数据会广播给所有订阅者 3-❌ 错误做法:同一个工人实例订阅多次 4-✅ 执行流程是并行的 5-👍🏻消费能力推荐 2-动手实操 1-Publisher 和 Subscriber示例 2-Publisher 和 多个Subscriber示例 3-难度升级-成功/失败记录 3-问题详解 1-subscription.request(n)执行解读 一、用工厂视角理解整个流程 1-角色映射 2-完整流程 二、关于 request(n) 的关系和含义 1-两个 request 之间的关系 2-request(3) 中 3 的含义 3-两个数值必须相同吗? 4-不同数值组合的效果演示 三、你代码中的执行流程时序图 四、关键要点总结 2-Publisher 和 多个Subscriber示例 一、同一个Publisher支持多个Subscriber 二、多订阅者的核心特性 1. 每个Worker独立维护自己的需求计数器 2. 数据会广播给所有订阅者 3. 执行流程是并行的 三、特殊场景:同一个Subscriber多次订阅 四、实际应用场景 场景1:日志监控系统 场景2:数据分发系统 五、重要注意事项 1. 背压独立 2. 异常隔离 3. 性能影响 4. 线程安全 六、扩展:Processor(中间加工者) 总结)

1-疑问总结
1-👩🏻🦰WebFlux角色扮演
### 角色映射
- Publisher(发布者) = 工厂:生产数据(产品)
- Subscriber(订阅者) = 应聘工人:处理数据(干活)
- Subscription(订阅关系) = 劳动合同:连接工厂和工人的契约
- request(n) = 工人向工厂要活干:"我现在能处理n个产品"
2-✅ 数据会广播给所有订阅者
// ✅ 一个工厂多个工人,但是工人之间不可以协同消费,数据会广播给所有订阅者
publisher.subscribe(worker1);
publisher.subscribe(worker2);
工厂生产:产品-0
├── 工人1收到:产品-0(处理慢)
└── 工人2收到:产品-0(处理快)
工厂生产:产品-1
├── 工人1收到:产品-1
└── 工人2收到:产品-1
3-❌ 错误做法:同一个工人实例订阅多次
// ❌ 错误做法:同一个工人实例订阅多次
Subscriber<String> worker = new MySubscriber();
publisher.subscribe(worker);
publisher.subscribe(worker); // 第二次订阅会怎样?
// 结果:第二个订阅会被忽略!
// 因为SubmissionPublisher内部会检查,同一个Subscriber只能订阅一次
4-✅ 执行流程是并行的
// 不同工人的消费能力不同,不会阻塞其他工人的消费
时间线:
t0: 工厂生产"产品-0"
├─ 工人1:收到"产品-0",开始处理(需要100ms)
└─ 工人2:收到"产品-0",开始处理(需要10ms)
t1: 工厂生产"产品-1"
├─ 工人1:还在处理"产品-0",等处理完才会收到"产品-1"
└─ 工人2:已处理完"产品-0",立即收到"产品-1"
结论:每个工人的处理速度独立,互不影响
5-👍🏻消费能力推荐
// 场景1:每次要1个(保守型)
onSubscribe: request(1)
onNext: request(1) // 每次1个,串行处理
// 【👍🏻推荐】场景2:逐步加速(自适应型)
onSubscribe: request(1)
onNext: request(3) // 第一次后每次3个
// 场景3:一次要完(激进型)
onSubscribe: request(10) // 一次要10个
// 不推荐:可能撑爆缓冲区
2-动手实操
1-Publisher 和 Subscriber示例
java
import lombok.SneakyThrows;
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;
import java.util.concurrent.TimeUnit;
public class ReactiveStreamDemo01 {
@SneakyThrows
public static void main(String[] args) {
// 1. 创建一个发布者
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
// 2. 创建一个订阅者
Flow.Subscriber<String> subscriber = new Flow.Subscriber<>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
System.out.println("建立订阅关系");
// 请求一个数据(背压控制)
subscription.request(1);
}
@Override
public void onNext(String item) {
System.out.println("接收到数据: " + item);
// 处理完一个再请求下一个
subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
System.out.println("发生错误: " + throwable.getMessage());
}
@Override
public void onComplete() {
System.out.println("所有数据处理完毕");
}
};
// 3. 建立订阅关系
publisher.subscribe(subscriber);
// 4. 发送数据
for (int i = 0; i < 10; i++) {
publisher.submit("hello reactive stream:" + i);
}
// 5. 关闭发布者
publisher.close();
// TODO 注意:整理要进行测试,要进行阻塞才能体会到日志打印
TimeUnit.HOURS.sleep(1);
}
}
- 打印日志
2-Publisher 和 多个Subscriber示例
多个Subscriber,每个Subscriber都会收到一份【全量任务】,和Kafka不同(Kafka是协同消费)
java
import lombok.SneakyThrows;
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;
import java.util.concurrent.TimeUnit;
public class ReactiveStreamDemo02 {
@SneakyThrows
public static void main(String[] args) {
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
// 工人1:普通工人,处理慢一点
Flow.Subscriber<String> worker1 = new Flow.Subscriber<>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
System.out.println("【工人1】签订合同,我要1个");
subscription.request(1);
}
@SneakyThrows
@Override
public void onNext(String item) {
System.out.println("【工人1】处理: " + item);
// 模拟任务耗时
Thread.sleep(100);
// 任务完成之后继续请求
subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
System.out.println("【工人1】完成所有工作");
}
};
// 工人2:快枪手,一次要3个
Flow.Subscriber<String> worker2 = new Flow.Subscriber<>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
System.out.println("【工人2】签订合同,我要3个");
subscription.request(3);
}
@Override
public void onNext(String item) {
System.out.println("【工人2】处理: " + item);
subscription.request(3);
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
System.out.println("【工人2】完成所有工作");
}
};
// 工厂雇佣两个工人
publisher.subscribe(worker1);
publisher.subscribe(worker2);
// 工厂生产10个产品
for (int i = 0; i < 10; i++) {
publisher.submit("产品-" + i);
}
publisher.close();
TimeUnit.SECONDS.sleep(5);
}
}
-
打印日志
【工人2】签订合同,我要3个
【工人1】签订合同,我要1个
【工人2】处理: 产品-0
【工人2】处理: 产品-1
【工人2】处理: 产品-2
【工人2】处理: 产品-3
【工人2】处理: 产品-4
【工人2】处理: 产品-5
【工人2】处理: 产品-6
【工人2】处理: 产品-7
【工人2】处理: 产品-8
【工人2】处理: 产品-9
【工人2】完成所有工作
【工人1】处理: 产品-0
【工人1】处理: 产品-1
【工人1】处理: 产品-2
【工人1】处理: 产品-3
【工人1】处理: 产品-4
【工人1】处理: 产品-5
【工人1】处理: 产品-6
【工人1】处理: 产品-7
【工人1】处理: 产品-8
【工人1】处理: 产品-9
【工人1】完成所有工作
3-难度升级-成功/失败记录
增加难度,订阅者在处理任务中随机出错,任务结束之后要收集成功任务和失败任务列表,并记录失败任务的原因
java
import lombok.SneakyThrows;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ReactiveStreamDemo03 {
@SneakyThrows
public static void main(String[] args) {
// 1. 创建一个发布者
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
// 用于收集任务结果
List<String> successTasks = new ArrayList<>();
List<FailedTask> failedTasks = new ArrayList<>();
AtomicInteger taskCounter = new AtomicInteger(0);
// 2. 创建一个订阅者(增加随机出错逻辑)
Flow.Subscriber<String> subscriber = new Flow.Subscriber<>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
System.out.println("建立订阅关系");
// 请求一个数据(背压控制)
subscription.request(1);
}
@Override
public void onNext(String item) {
int taskId = taskCounter.incrementAndGet();
System.out.println("开始处理任务 #" + taskId + ": " + item);
try {
// 模拟任务处理耗时
TimeUnit.MILLISECONDS.sleep(100);
// 随机出错:30%的概率失败
if (Math.random() < 0.3) {
// 随机生成不同的错误类型
int errorType = (int) (Math.random() * 3);
String errorMsg = switch (errorType) {
case 0 -> "数据格式错误: 包含非法字符";
case 1 -> "超时错误: 处理时间超过限制";
case 2 -> "业务逻辑错误: 数据不符合业务规则";
default -> "未知错误";
};
throw new RuntimeException(errorMsg);
}
// 任务成功
System.out.println("✅ 任务 #" + taskId + " 处理成功: " + item);
synchronized (successTasks) {
successTasks.add(item);
}
} catch (Exception e) {
// 任务失败
String errorMsg = e.getMessage();
System.out.println("❌ 任务 #" + taskId + " 处理失败: " + errorMsg);
synchronized (failedTasks) {
// 构建异常任务对象
failedTasks.add(new FailedTask(taskId, item, errorMsg));
}
// 处理失败时,可以选择不中断流程,继续处理下一个任务
// 这里我们继续处理,但也可以选择取消订阅
// subscription.cancel(); // 如果需要中断则取消注释
} finally {
// 处理完一个再请求下一个
subscription.request(1);
}
}
@Override
public void onError(Throwable throwable) {
System.out.println("订阅者发生严重错误: " + throwable.getMessage());
// 打印堆栈信息
throwable.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("\n========== 所有数据处理完毕 ==========");
printTaskReport();
}
private void printTaskReport() {
System.out.println("📊 任务执行报告:");
System.out.println("总任务数: " + (successTasks.size() + failedTasks.size()));
System.out.println("✅ 成功任务数: " + successTasks.size());
System.out.println("❌ 失败任务数: " + failedTasks.size());
if (!successTasks.isEmpty()) {
System.out.println("\n成功任务列表:");
successTasks.forEach(task -> System.out.println(" - " + task));
}
if (!failedTasks.isEmpty()) {
System.out.println("\n失败任务列表:");
failedTasks.forEach(task -> {
System.out.println(" - 任务ID: " + task.taskId +
", 内容: " + task.content +
", 原因: " + task.reason);
});
}
}
};
// 3. 建立订阅关系
publisher.subscribe(subscriber);
// 4. 发送数据
System.out.println("开始发送10个任务...");
for (int i = 0; i < 10; i++) {
publisher.submit("task-data-" + i);
}
// 5. 关闭发布者
publisher.close();
System.out.println("发布者已关闭,等待所有任务处理完成...");
// 等待所有任务处理完成
TimeUnit.SECONDS.sleep(5);
// 额外输出一次最终报告(因为onComplete可能在等待时已经执行)
System.out.println("\n========== 最终统计 ==========");
System.out.println("成功任务数: " + successTasks.size());
System.out.println("失败任务数: " + failedTasks.size());
if (!failedTasks.isEmpty()) {
System.out.println("失败任务详情:");
failedTasks.forEach(task ->
System.out.println(" - ID:" + task.taskId + " 内容:" + task.content + " 原因:" + task.reason)
);
}
}
// 失败任务记录类
static class FailedTask {
private final int taskId;
private final String content;
private final String reason;
public FailedTask(int taskId, String content, String reason) {
this.taskId = taskId;
this.content = content;
this.reason = reason;
}
}
}
-
日志打印
开始发送10个任务...
建立订阅关系
发布者已关闭,等待所有任务处理完成...
开始处理任务 #1: task-data-0
✅ 任务 #1 处理成功: task-data-0
开始处理任务 #2: task-data-1
❌ 任务 #2 处理失败: 超时错误: 处理时间超过限制
开始处理任务 #3: task-data-2
✅ 任务 #3 处理成功: task-data-2
开始处理任务 #4: task-data-3
✅ 任务 #4 处理成功: task-data-3
开始处理任务 #5: task-data-4
✅ 任务 #5 处理成功: task-data-4
开始处理任务 #6: task-data-5
✅ 任务 #6 处理成功: task-data-5
开始处理任务 #7: task-data-6
✅ 任务 #7 处理成功: task-data-6
开始处理任务 #8: task-data-7
❌ 任务 #8 处理失败: 数据格式错误: 包含非法字符
开始处理任务 #9: task-data-8
✅ 任务 #9 处理成功: task-data-8
开始处理任务 #10: task-data-9
✅ 任务 #10 处理成功: task-data-9========== 所有数据处理完毕 ==========
📊 任务执行报告:
总任务数: 10
✅ 成功任务数: 8
❌ 失败任务数: 2成功任务列表:
- task-data-0
- task-data-2
- task-data-3
- task-data-4
- task-data-5
- task-data-6
- task-data-8
- task-data-9失败任务列表:
- 任务ID: 2, 内容: task-data-1, 原因: 超时错误: 处理时间超过限制
- 任务ID: 8, 内容: task-data-7, 原因: 数据格式错误: 包含非法字符========== 最终统计 ==========
成功任务数: 8
失败任务数: 2
失败任务详情:
- ID:2 内容:task-data-1 原因:超时错误: 处理时间超过限制
- ID:8 内容:task-data-7 原因:数据格式错误: 包含非法字符
3-问题详解
1-subscription.request(n)执行解读
2个方法中subscription.request(1)之间是什么关系?具体的处理流程是怎样?
我来用"工厂招工"的视角解释这个流程,并回答你的问题。
一、用工厂视角理解整个流程
1-角色映射
- Publisher(发布者) = 工厂:生产数据(产品)
- Subscriber(订阅者) = 应聘工人:处理数据(干活)
- Subscription(订阅关系) = 劳动合同:连接工厂和工人的契约
- request(n) = 工人向工厂要活干:"我现在能处理n个产品"
2-完整流程
【1. 工厂开业】
Publisher publisher = new SubmissionPublisher<>();
→ 工厂建立,准备生产产品
【2. 工人应聘】
publisher.subscribe(subscriber);
→ 工人到工厂应聘
【3. 签订合同】
onSubscribe(Flow.Subscription subscription)
→ 工厂和工人签订劳动合同(subscription)
→ 工人说:"我先要1个产品来试试" subscription.request(1)
【4. 工厂派活】
for (int i = 0; i < 10; i++) {
publisher.submit("hello reactive stream:" + i);
}
→ 工厂开始生产10个产品,但不会一次全给工人
→ 因为工人说了只要1个,所以先给1个
【5. 工人干活】
onNext(String item)
→ 工人收到1个产品,开始处理
→ 处理完后说:"我再要3个产品" subscription.request(3)
【6. 循环往复】
→ 工厂收到请求,再给3个
→ 工人处理完,再要3个
→ 直到所有产品处理完 或 工厂关闭
【7. 工厂关门】
publisher.close();
→ 工厂不再生产新产品
→ 工人处理完剩余产品后收到 onComplete()
二、关于 request(n) 的关系和含义
1-两个 request 之间的关系
它们是独立的请求,每次调用都表示"新增需求",不是覆盖关系:
java
onSubscribe: subscription.request(1); // 需求总量 +1
onNext第1次: subscription.request(3); // 需求总量 +3
onNext第2次: subscription.request(3); // 需求总量 +3
...
需求计数机制(内部维护一个计数器):
初始需求 = 0
onSubscribe: request(1) → 需求 = 1
→ 发送1个数据,需求变为0
onNext: request(3) → 需求 = 3
→ 发送3个数据,需求变为0
onNext: request(3) → 需求 = 3
→ 发送3个数据,需求变为0
...
2-request(3) 中 3 的含义
表示"本次新增请求3个数据",是一个增量计数,不是总共要3个。
3-两个数值必须相同吗?
完全不需要相同! 这两个数值是独立的:
| 对比维度 | onSubscribe中的request(1) | onNext中的request(3) |
|---|---|---|
| 执行时机 | 订阅建立时执行1次 | 每次收到数据后执行 |
| 业务含义 | 初始试探:"先要1个试试" | 正常处理:"一次要3个提高效率" |
| 数值建议 | 通常为1(试探性) | 根据处理能力灵活调整 |
4-不同数值组合的效果演示
java
// 场景1:每次要1个(保守型)
onSubscribe: request(1)
onNext: request(1) // 每次1个,串行处理
// 场景2:逐步加速(自适应型)
onSubscribe: request(1)
onNext: request(3) // 第一次后每次3个
// 场景3:一次要完(激进型)
onSubscribe: request(10) // 一次要10个
// 不推荐:可能撑爆缓冲区
三、你代码中的执行流程时序图
时间线:
t0: publisher.subscribe(subscriber)
→ 调用 subscriber.onSubscribe()
→ subscription.request(1) 【需求+1,总需求=1】
t1: publisher.submit("数据0")
→ 需求=1 > 0,发送数据0,需求变为0
→ 调用 subscriber.onNext("数据0")
→ subscription.request(3) 【需求+3,总需求=3】
t2: publisher.submit("数据1")
→ 需求=3 > 0,发送数据1,需求变为2
→ 调用 subscriber.onNext("数据1")
→ subscription.request(3) 【需求+3,总需求=5】
t3: publisher.submit("数据2")
→ 需求=5 > 0,发送数据2,需求变为4
→ 调用 subscriber.onNext("数据2")
→ subscription.request(3) 【需求+3,总需求=7】
... 继续直到所有数据发送完毕
四、关键要点总结
- request是增量请求:每次调用都是在已有需求基础上增加
- 背压控制的核心:工人根据自己处理能力灵活请求数据
- 数值完全独立:初始请求1个只是为了建立连接,后续可以根据实际情况调整
- 默认缓冲机制:如果生产者速度 > 消费者速度,未请求的数据会暂存在缓冲区
建议将你的代码改成更合理的配置:
java
onSubscribe: subscription.request(3); // 初始请求3个,提高启动效率
onNext: subscription.request(1); // 处理完一个要一个,平滑处理
// 或者
onSubscribe: subscription.request(5); // 初始请求5个
onNext: subscription.request(2); // 每次追加2个,保持一定缓冲
这样的设计让生产者(工厂)和消费者(工人)能够高效协作,既不会让工人累死(请求太多),也不会让工厂闲置(请求太少)。
2-Publisher 和 多个Subscriber示例
可以! 一个工厂(Publisher)完全可以雇佣多个工人(Subscriber),这是Reactive Streams的核心特性之一------多播(Multicast)。
一、同一个Publisher支持多个Subscriber
java
public class MultiSubscriberDemo {
@SneakyThrows
public static void main(String[] args) {
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
// 工人1:普通工人,处理慢一点
Flow.Subscriber<String> worker1 = new Flow.Subscriber<>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
System.out.println("【工人1】签订合同,我要1个");
subscription.request(1);
}
@Override
public void onNext(String item) {
System.out.println("【工人1】处理: " + item);
try { Thread.sleep(100); } catch (InterruptedException e) {}
subscription.request(1);
}
@Override
public void onError(Throwable throwable) {}
@Override
public void onComplete() {
System.out.println("【工人1】完成所有工作");
}
};
// 工人2:快枪手,一次要3个
Flow.Subscriber<String> worker2 = new Flow.Subscriber<>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
System.out.println("【工人2】签订合同,我要3个");
subscription.request(3);
}
@Override
public void onNext(String item) {
System.out.println("【工人2】处理: " + item);
subscription.request(3);
}
@Override
public void onError(Throwable throwable) {}
@Override
public void onComplete() {
System.out.println("【工人2】完成所有工作");
}
};
// 工厂雇佣两个工人
publisher.subscribe(worker1);
publisher.subscribe(worker2);
// 工厂生产10个产品
for (int i = 0; i < 10; i++) {
publisher.submit("产品-" + i);
}
publisher.close();
TimeUnit.SECONDS.sleep(5);
}
}
二、多订阅者的核心特性
1. 每个Worker独立维护自己的需求计数器
java
工人1的需求:独立计数
工人2的需求:独立计数
互不干扰!
2. 数据会广播给所有订阅者
工厂生产:产品-0
├── 工人1收到:产品-0(处理慢)
└── 工人2收到:产品-0(处理快)
工厂生产:产品-1
├── 工人1收到:产品-1
└── 工人2收到:产品-1
注意 :每个工人都会收到所有数据,除非使用了特殊的过滤机制。
3. 执行流程是并行的
时间线:
t0: 工厂生产"产品-0"
├─ 工人1:收到"产品-0",开始处理(需要100ms)
└─ 工人2:收到"产品-0",开始处理(需要10ms)
t1: 工厂生产"产品-1"
├─ 工人1:还在处理"产品-0",等处理完才会收到"产品-1"
└─ 工人2:已处理完"产品-0",立即收到"产品-1"
结论:每个工人的处理速度独立,互不影响
三、特殊场景:同一个Subscriber多次订阅
java
// ❌ 错误做法:同一个工人实例订阅多次
Subscriber<String> worker = new MySubscriber();
publisher.subscribe(worker);
publisher.subscribe(worker); // 第二次订阅会怎样?
// 结果:第二个订阅会被忽略!
// 因为SubmissionPublisher内部会检查,同一个Subscriber只能订阅一次
四、实际应用场景
场景1:日志监控系统
java
SubmissionPublisher<LogEvent> logPublisher = new SubmissionPublisher<>();
// 工人1:写日志到文件
Subscriber<LogEvent> fileWriter = new FileLogSubscriber();
// 工人2:发送告警(只关注ERROR级别)
Subscriber<LogEvent> alertSender = new AlertSubscriber();
// 工人3:实时展示到控制台
Subscriber<LogEvent> consoleDisplay = new ConsoleSubscriber();
logPublisher.subscribe(fileWriter);
logPublisher.subscribe(alertSender);
logPublisher.subscribe(consoleDisplay);
// 一条日志,三个工人各司其职
logPublisher.submit(new LogEvent("ERROR", "系统崩溃"));
场景2:数据分发系统
java
SubmissionPublisher<Order> orderPublisher = new SubmissionPublisher<>();
// 工人1:库存系统(需要全部订单)
Subscriber<Order> inventorySystem = new InventorySubscriber();
// 工人2:财务系统(只关注已支付订单)
Subscriber<Order> financeSystem = new FinanceSubscriber();
// 工人3:物流系统(只关注待发货订单)
Subscriber<Order> logisticsSystem = new LogisticsSubscriber();
orderPublisher.subscribe(inventorySystem);
orderPublisher.subscribe(financeSystem);
orderPublisher.subscribe(logisticsSystem);
五、重要注意事项
1. 背压独立
java
工人1:request(1) → 慢速处理,每次1个
工人2:request(10) → 快速处理,每次10个
// 工厂会根据每个工人的能力分别控制发送速度
// 不会因为工人2处理快就多给工人1
2. 异常隔离
java
工人1:发生异常 → onError(),不影响工人2
工人2:继续正常工作
3. 性能影响
java
// 订阅者越多,数据复制开销越大
publisher.subscribe(worker1);
publisher.subscribe(worker2);
publisher.subscribe(worker3);
// 每个数据需要复制3份发送给3个工人
4. 线程安全
java
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
// 默认使用ForkJoinPool.commonPool()并行处理
// 多个订阅者可能在不同线程中并发处理数据
六、扩展:Processor(中间加工者)
java
// Processor既是Subscriber又是Publisher
// 可以形成处理链:Publisher → Processor1 → Processor2 → Subscriber
public class MultiStageDemo {
public static void main(String[] args) {
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
// 加工站1:转换数据(转大写)
TransformProcessor<String, String> upperProcessor = new TransformProcessor<>();
// 加工站2:过滤数据(只保留包含"重要"的)
FilterProcessor<String> filterProcessor = new FilterProcessor<>();
// 最终工人
Subscriber<String> finalWorker = new FinalSubscriber();
// 建立处理链
publisher.subscribe(upperProcessor);
upperProcessor.subscribe(filterProcessor);
filterProcessor.subscribe(finalWorker);
// 发布数据
publisher.submit("重要消息");
publisher.submit("普通消息");
publisher.submit("重要通知");
}
}
总结
| 问题 | 答案 |
|---|---|
| 一个Publisher可以订阅多个Subscriber吗? | ✅ 可以,无限多个 |
| 数据会发给所有Subscriber吗? | ✅ 默认全部广播 |
| 每个Subscriber的背压独立吗? | ✅ 完全独立 |
| 一个Subscriber可以订阅多个Publisher吗? | ✅ 可以,但需要管理多个Subscription |
| 执行是并行还是串行? | 默认并行(ForkJoinPool) |
回到工厂视角:
- 一个工厂(Publisher)可以雇佣无数个工人(Subscriber)
- 每个工人独立领活(request),独立干活(onNext)
- 工厂生产一个产品,所有工人人手一份
- 工人之间互不干扰,效率各不相同
这种设计让Reactive Streams非常灵活,适合实现发布-订阅模式、事件驱动架构、数据管道等场景。