WebFlux_学习Subscriber总结

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】

... 继续直到所有数据发送完毕

四、关键要点总结

  1. request是增量请求:每次调用都是在已有需求基础上增加
  2. 背压控制的核心:工人根据自己处理能力灵活请求数据
  3. 数值完全独立:初始请求1个只是为了建立连接,后续可以根据实际情况调整
  4. 默认缓冲机制:如果生产者速度 > 消费者速度,未请求的数据会暂存在缓冲区

建议将你的代码改成更合理的配置:

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非常灵活,适合实现发布-订阅模式、事件驱动架构、数据管道等场景。


相关推荐
GlueNa2SiO31 小时前
10-Docker生产环境部署与K8s入门
笔记·学习·docker·容器·kubernetes
白露与泡影1 小时前
Java面试题及答案整理(2026年金九银十最新版,持续更新)
java·开发语言
茯苓gao1 小时前
无感FOC核心原理:没有编码器,电机如何获得转子电角度?
笔记·嵌入式硬件·学习
少控科技1 小时前
农场设备管理代码(1)
开发语言·c#
❀搜不到1 小时前
isat-sam分割导出掩码图
开发语言·python
geovindu1 小时前
java: Memento Pattern
java·开发语言·后端·备忘录模式·行为模式
xcLeigh1 小时前
Unity基础:Start与Update方法——Unity脚本生命周期初探
java·unity·游戏引擎·教程
zephyr052 小时前
链表实现O(n log n)时间复杂度的排序——归并排序详解
java·数据结构·算法
曾阿伦2 小时前
Trae CN Python环境调试debug指南
开发语言·python