读者画像
本书面向三类读者:
- 写过异步代码但背压总调不对的后端开发:你已经用过
CompletableFuture、甚至跑过WebFlux,但当服务出现 OOM 或下游被打爆时,不知道问题出在哪一层。本书帮你建立「从信号契约到策略选择」的完整判断链。 - 想了解响应式原理而非只记操作符的人:市面上多数 Reactor 教程停留在「map 怎么用」「flatMap 和 concatMap 区别是什么」。本书从 Reactive Streams 规范出发,让你知道为什么是 map 而不是 flatMap、为什么 request(1) 和 request(Long.MAX_VALUE) 会导致完全不同的内存曲线。
- 其他语言转 Java 的工程师:如果你从 JavaScript(RxJS)、Kotlin(Flow)或 Rust(futures-rs)过来,本书帮你建立 Java 生态的响应式概念映射——哪些是语言无关的(RS 规范),哪些是框架特异的(Reactor 的
Schedulers、RxJava 的Subject)。
前置知识
- Java 语法:类、接口、Lambda、泛型、异常处理。如果你读过《Java 编程入门》或同等水平的语法书,已足够。
- Stream API:
stream().filter().map().collect()的用法。本书把 Stream 的「惰性求值」推进到「背压控制」,但不会从头讲 Stream 基础。 - 并发基础:
ExecutorService、Future、Thread的基本概念。本书在第 6 章(调度器)引用这些概念,但不会展开线程状态迁移或锁优化(已有《Java 并发编程》三卷覆盖)。 - Maven 多模块:能理解
pom.xml里的dependencyManagement、module、plugin。本书使用的结构是标准 Maven 多模块,无特殊插件。
不需要前置:Netty 源码、Spring 容器启动、Kafka 分区机制、gRPC 协议。这些留给卷二/卷三,本卷只给一句话边界。
环境清单
以下版本全书统一,动笔前请先在本机复现。
| 组件 | 版本 | 验证命令 |
|---|---|---|
| JDK | Temurin 25.0.5+8 | java -version |
| Maven | 3.9.12 | mvn -version |
| JUnit Jupiter | 5.14.4 | 见 pom.xml |
| Project Reactor | BOM 2025.0.8 | 见 pom.xml |
| RxJava | 3.1.12 | 见 pom.xml |
| RS TCK | 1.0.4 | 见 pom.xml |
本机口径(所有「本机输出」均来自此环境):
Apple M1 Pro,10 核,32 GB,macOS 26.3 (25D125)
Temurin 25.0.5+8
环境验证
1. 检查 JDK
export JAVA_HOME=~/.jdks/jdk-25.0.5+8/Contents/Home
export PATH="$JAVA_HOME/bin:$PATH"
java -version
预期输出:
openjdk version "25.0.5" 2026-10-20 LTS
OpenJDK Runtime Environment Temurin-25.0.5+8 (build 25.0.5+8-LTS)
OpenJDK 64-Bit Server VM Temurin-25.0.5+8 (build 25.0.5+8-LTS, mixed mode, sharing)
2. 检查 Maven
mvn -version
预期输出(前两行):
Apache Maven 3.9.12 (848fbb4bf2d427b72bdb2471c22fced7ebd9a7a1)
Maven home: /Users/bingrong.yan/apache-maven-3.9.12
Java version: 25.0.5, vendor: Eclipse Adoptium, runtime: /Users/bingrong.yan/.jdks/jdk-25.0.5+8/Contents/Home
3. eventd-v1 骨架编译
本书的贯穿项目 eventd-v1 是一个多模块 Maven 工程,位于项目仓库的 .local/java_reactive/eventd-v1/ 目录下(不进入 Hugo 构建,仅作为代码验证用)。
cd .local/java_reactive/eventd-v1
mvn -q -DskipTests compile
预期无输出(-q 安静模式)且返回码为 0。如果有依赖下载,首次编译可能需要 1–2 分钟。
eventd-v1 项目结构
eventd-v1/
├── pom.xml # 父 POM,Reactor BOM 2025.0.8
├── eventd-core/ # RS 规范实现与工具类
│ ├── pom.xml
│ └── src/
│ ├── main/java/com/plume/eventd/core/
│ │ ├── SyncSinglePublisher.java # 同步单值 Publisher
│ │ ├── AsyncRangePublisher.java # 异步范围 Publisher(带背压)
│ │ ├── LoggingSubscriber.java # 通用日志 Subscriber
│ │ ├── MapProcessor.java # map 操作符 Processor
│ │ ├── SensorSimulatorPublisher.java # 传感器模拟器
│ │ └── ...(随章节逐步添加)
│ └── test/java/com/plume/eventd/core/
│ ├── SyncSinglePublisherTckTest.java # RS TCK 合规测试
│ └── ...(随章节逐步添加)
└── eventd-app/ # 背压演示应用
├── pom.xml
└── src/main/java/com/plume/eventd/app/
├── BackpressureDashboard.java # 背压统计面板
└── EventdApplication.java # 入口
这个树是全书的目标结构,不代表仓库快照已经全部包含。截至 14.3 的验收记录,eventd-core 实际只有 SyncSinglePublisher 和 LoggingSubscriber 两个类,eventd-app 的 src/ 为空,TCK 测试类也没有进入仓库;其余类都是章节示例。读代码时以各节给出的完整类为准。
模块依赖关系:
eventd-app
└── depends on eventd-core
└── depends on reactor-core (via BOM)
└── depends on rxjava (direct)
└── depends on reactive-streams-tck (test scope)
代码约定
包名
全书统一 com.plume.eventd 包及其子包:
com.plume.eventd.core:RS 规范实现、工具类、操作符com.plume.eventd.app:演示应用与入口
类命名
- Publisher 实现以
*Publisher结尾(如SyncSinglePublisher) - Subscriber 实现以
*Subscriber结尾(如LoggingSubscriber) - Processor 实现以
*Processor结尾(如MapProcessor) - 应用类以功能命名(如
BackpressureDashboard、SensorSimulatorPublisher)
编译目标
<properties>
<maven.compiler.release>25</maven.compiler.release>
</properties>
不使用 --enable-preview,不使用 JDK 新特性(除非书中明确讲解)。java.util.concurrent.Flow(JDK 9+)中的 Publisher/Subscriber/Subscription 与 org.reactivestreams 包中的接口形状一致、语义等价,但类型不同、不能直接赋值。本卷第 2–3 章的手写实现统一使用 org.reactivestreams,因为第 11 章的普通 TCK 和 Reactor 的 subscribe 都直接接受这个包的类型;13.1 的 eventd-core 现有类用的是 Flow,该节会给出 FlowAdapters 适配路线。
日志
全书正文示例默认不用 SLF4J/Logback,统一用 System.getLogger(JDK 标准)或直接 System.out.println。原因是:
- 减少依赖,降低环境搭建门槛。
System.getLogger在 JDK 25 中已足够用于书中演示级别的日志输出。- 避免 SLF4J 绑定版本冲突(这在 Reactor/RxJava 多依赖场景下常见)。
唯一例外是 12.2:Reactor 的 Flux.log() 本身通过 SLF4J 输出信号流,没有日志后端就看不到任何内容,所以那一节会临时引入 slf4j-simple,并说明它只是演示用。
换行与编码
- 源文件 UTF-8,
\n换行。 - 每行不超过 120 列。
- 使用 4 空格缩进(不混合 tab)。
代码用例的三种标记
| 标记 | 含义 | 示例 |
|---|---|---|
| 可运行 | 完整类,可直接 javac + java 或通过 JUnit 运行 | 完整 class 声明 + main 或 @Test |
| 片段 | 不完整类,需要按声明顺序补充字段、import 才能编译 | 省略 import 或字段声明 |
| 反例 | 故意错误,不会编译或运行时必抛异常 | 注释标注「反例:以下代码错误」 |
可运行的代码在书中用完整类展示,片段用省略号 ... 标注缺失部分,反例用代码块内的注释说明预期错误。
阅读方式
顺序通读(推荐初次阅读)
按章顺序:序 → 前言 → 目录 → 第 1 章 → … → 第 14 章 → 附录。
每节末尾有「阅读导航」,指向前一篇和后一篇。前置(序、前言、目录)和附录没有导航。
机制跳读
如果你对 RS 规范已有了解,可直接跳到:
- 第 2–3 章:手写实现(验证你的理解)
- 第 7 章:背压策略(生产最常用)
- 第 11 章:RS TCK(验证合规性)
- 第 12 章:调试(排障必备)
跳读时请回头参考目录页的「章节依赖关系」图,确认前置知识已覆盖。
只看代码
如果你只想运行示例:读前言(环境配置)→ 第 2–3 章(实现代码)→ 第 13–14 章(eventd 验收)→ 附录 A(操作符速查)。其他章节全跳过。
四道验证
本书每节代码经过以下四级验证:
L1:结构检查
description120–200 字符(中文按字符计)slug == 文件名且全局唯一- 正文从
h2起,不跳级 - 代码围栏标语言
- 阅读导航前后衔接
- 无
TODO/待补充/此处省略
L2:编译验证
完整项目编译:
cd .local/java_reactive/eventd-v1
mvn -q -DskipTests compile
单文件编译(含 main 方法):
export JAVA_HOME=~/.jdks/jdk-25.0.5+8/Contents/Home
javac --release 25 SyncSinglePublisher.java
L3:运行验证
背压演示应用:
cd eventd-app
mvn -q exec:java -Dexec.mainClass="com.plume.eventd.app.EventdApplication"
RS TCK 测试(需要先按第 11 章把测试类加入 eventd-core/src/test/java;当前仓库快照没有这个目录,14.3 会记录实际失败):
cd eventd-core
mvn test -Dtest='*TckTest'
L4:产物验证
内容加入 Hugo 后:
cd /Users/bingrong.yan/projects/birdor/plumephp
hugo --gc --minify 2>&1 | grep -E "ERROR|WARN" || echo "构建干净"
关于 Reactive Streams 的版本
你可能注意到 JDK 内置了 java.util.concurrent.Flow(JDK 9+),但同时存在独立的 org.reactivestreams 依赖。两者接口定义完全一致,但:
- JDK
Flow:标准库内置,无额外依赖,适合展示和学习。 org.reactivestreams:独立的 jar,RS TCK 测试需要它(TCK 的基类引用此包的接口)。
本卷的示例实现使用 org.reactivestreams 接口,与 TCK 和 Reactor 保持同一套类型;13.1 的 eventd-core 因历史原因使用 JDK Flow,该节单独说明迁移与适配。TCK 有两个 artifact:reactive-streams-tck-flow 直接验证 Flow 类型,reactive-streams-tck 验证 org.reactivestreams 类型。两套接口语义等价,但类型不同,跨包传递时要用 FlowAdapters 转换,不能直接赋值。
关于 Project Reactor 与 RxJava 的选择
Spring 生态主推 Project Reactor(reactor-core),Android 和遗留系统常用 RxJava 3。本卷两者都覆盖:
- Project Reactor:第 4–9 章主力讲解,与 Spring 生态无缝衔接。
- RxJava 3:第 10 章专门对照,帮助已有 RxJava 经验的读者迁移,或需要同时维护两套代码的工程师理解差异。
这不是一场宗教战争。选择 Reactor 还是 RxJava 取决于你的技术栈——本书的目标是让无论选哪个,你都知道底层在发生什么。
关于 macOS 的特有条件
本书在 macOS 上编写和测试,以下事实可能影响部分输出:
- macOS 没有
ss命令。连接诊断用netstat -anv -p tcp、lsof -nP -iTCP:9090。 tcpdump需要sudo,loopback 用-i lo0。没有实际执行就不要写「本机输出」。- macOS 没有 epoll;Reactor Netty 默认使用 nio+KQueue(卷二再展开)。
ab(Apache Bench)可用(/usr/sbin/ab);wrk、hey未安装,不假设存在。
如果你在 Linux 上跟做,行为基本一致,但部分系统命令(如 ss)的输出格式可能不同。
版本与勘误
本书基于以下版本锁定编写。后续版本变化将在附录中标注:
| 日期 | 事件 |
|---|---|
| 2026-11-03 | 初稿完成,Reactor BOM 2025.0.8、RxJava 3.1.12 |
| 2026-11-03 | JDK 25 LTS(Temurin 25.0.5+8) |
如发现与书中描述不符的版本行为(例如 Reactor 2026.x 删除了某个操作符),请通过站点反馈渠道提交。
全书路线图
第 1 章 Reactive Streams 规范(3 节) —— 信号契约与 43 条规则
第 2 章 从零实现 Publisher(3 节) —— 同步/异步 Publisher、Subscriber
第 3 章 Processor、操作符链与调度切换(3 节)—— Processor、map/filter/take、subscribeOn/publishOn
第 4 章 Mono 与 Flux(3 节) —— 创建、变换、组合
第 5 章 错误处理(3 节) —— 恢复、重试、超时、取消
第 6 章 调度器(3 节) —— single/elastic/parallel/custom
第 7 章 背压策略(3 节) —— buffer/drop/error/limitRate
第 8 章 Hot 与 Cold Publisher(3 节) —— 重放、广播、缓存
第 9 章 Sinks(3 节) —— 程序化发射、多播、重放
第 10 章 RxJava 3 对照(3 节) —— Subject、ConnectableObservable、迁移
第 11 章 RS TCK 合规测试(3 节) —— Publisher/Subscriber/Processor 验证
第 12 章 调试与生命周期(3 节) —— 钩子、检查点、装配时 vs 订阅时
第 13 章 eventd v1 架构与实现(3 节) —— core/app 模块、传感器模拟器、背压面板
第 14 章 Reactor 重写、性能基线与验收(3 节)—— 同一逻辑双写、性能基线、v1 验收清单
阅读导航
上一篇:序:从回调地狱到背压契约
下一篇:目录与学习路径
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。