前言:环境、项目与读法

本书前言:说明读者画像与前置知识,给出环境清单(JDK 25 + Reactor BOM 2025.0.8 + RxJava 3.1.12 + RS TCK 1.0.4),搭建 eventd-v1 多模块 Maven 骨架,约定代码风格、编译命令与验证方式,并列出全部依赖版本与真实输出供读者核对。

读者画像

本书面向三类读者:

  1. 写过异步代码但背压总调不对的后端开发:你已经用过 CompletableFuture、甚至跑过 WebFlux,但当服务出现 OOM 或下游被打爆时,不知道问题出在哪一层。本书帮你建立「从信号契约到策略选择」的完整判断链。
  2. 想了解响应式原理而非只记操作符的人:市面上多数 Reactor 教程停留在「map 怎么用」「flatMap 和 concatMap 区别是什么」。本书从 Reactive Streams 规范出发,让你知道为什么是 map 而不是 flatMap、为什么 request(1) 和 request(Long.MAX_VALUE) 会导致完全不同的内存曲线。
  3. 其他语言转 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 协议。这些留给卷二/卷三,本卷只给一句话边界。

环境清单

以下版本全书统一,动笔前请先在本机复现。

组件版本验证命令
JDKTemurin 25.0.5+8java -version
Maven3.9.12mvn -version
JUnit Jupiter5.14.4见 pom.xml
Project ReactorBOM 2025.0.8见 pom.xml
RxJava3.1.12见 pom.xml
RS TCK1.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。原因是:

  1. 减少依赖,降低环境搭建门槛。
  2. System.getLogger 在 JDK 25 中已足够用于书中演示级别的日志输出。
  3. 避免 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:结构检查

  • description 120–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-03JDK 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 验收清单

阅读导航

上一篇:序:从回调地狱到背压契约

下一篇:目录与学习路径

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「java」更多文章

  1. 15.3 全书总结与学习路径回顾
  2. 15.2 响应式流处理的演进趋势
  3. 15.1 引擎选型指南