1.Spring官方布道师Josh Long、Spring Reactor项目创始人Stephane Maldini以及业内专家翟永超、梁桂钊、方志斌、于文龙、尹相宇、刘嘉诚联袂力荐。
2.本书包含配套视频及源码资源,以及可以免费观看国外知名Java开发者的分享视频(中文字幕)。
3.本书主要专注于解读Spring Reactor 3的代码设计与实现,以揭示其中的设计精髓,帮助大家灵活运用及提升代码设计思维。
4.本书是学习响应式编程非常好的参考资料,是成体系的、传授编程思想和技巧的图书。
本书主要专注于解读Spring Reactor 3的代码设计与实现。全书共10章,其中第1、2章将从接口的设计入手,逐渐深入介绍Reactor中Flux源与订阅者Subscriber的诸多交互实现细节;第3章将通过对调度器的研究来向读者展示其中的优秀设计,可以帮助读者更好地掌握Java并发库,同时可以使读者对使用Reactor进行异步编程有更好的认识;第4章将接触到一些常用的Reactor操作,方便读者写出可重用度高、逻辑清晰的代码;第5、6、7章将着重分析Reactor中Processor的设计实现,不仅讲述了它的使用场景,还讲解了其中的内在原理,以及如何应对未来项目开发过程中可能遇到的种种问题;第8章将介绍并分析Reactor特别提供的Context,这是Reactor为了应对生产-订阅模式下的响应式编程在异步环境中对订阅关系上下文进行管理所产生的问题而给出的解决方案,Spring Framework 5.2中的响应式事务也是基于它实现的;第9章将主要介绍Reactor中的测试,同时带着读者一步一步设计实现一个针对Reactor项目的测试库;第10章将主要介绍Reactor中的调试,可以教会读者根据不同的需求采取不同的调试方式。
本书适合有Java编程基础的中高级Java开发工程师、想要学习代码设计思路与技巧的读者、对响应式编程感兴趣的读者阅读。
推荐序一
Towards a More Exciting, More Reactive Tomorrow
Hi, Spring fans! It's an interesting time to be alive. Today, the possible applications any programmer can build today are much more numerous than they were when I first started. The opportunities are so much more than they were before. It's possible to write code that runs on the server-side, on the backend, in giant systems, in big data platforms, in streaming platforms, on mobile phones, in cars, in the browser, on your watch, on your tablets, on your TVs, etc., all while using fairly similar languages, and while using similar skills. All of these destinations are also open and - often - open-source. It costs almost nothing to build this stuff. It takes time and it takes a computer with an internet connection. But, the tools are free. This is an ideal scenario. We can do almost anything today. I am very excited to see the opportunities expand in the last 20 years.
You know what I did not expect to happen so quickly? For the possibilities to become so good. I did not expect them to become so refined, so polished in so short a period of time. I was excited when Java ME came out. Now we have Android and iOS. I was excited when Hadoop came out. Now we have Spark and TensorFlow. I was excited when JDBC, the Servlet specification and Struts came out. Now we have Spring. I was excited when Netscape introduced JavaScript. Now we have Vue.js and React and Angular. I was excited when Spring came out. Now we have Spring Boot. I was excited when C++ came out. Now we have Kotlin. I was excited when Ant came out. Now we have Maven and Gradle. I was excited when the ideas around continuous delivery started to crystalize. Now we have a Gitops-centric culture powered by technologies like Kubernetes. Everything has gotten so much better in the last 20 years. All of these things were exciting to me when they first arrived. But they're better now. They're easier. They're faster. They're cheaper. They're a natural evolution of the ideas we've known for a long time.
I feel the same enthusiasm — excitement — when I look at reactive code. I love Spring. I know that it's one of the most powerful ways to express my microservices. Today, I am excited about the opportunity to use Spring and Reactor to build much more resource-efficient, easier-to-understand, reactive services.
Reactive Programming is a natural next step in the creation of cloud native applications. Reactive libraries offer me several tentpole benefits.
I’ll expand on those points here:
Reactive Programming offers one abstraction, no matter what the application (server-sent events, RSocket, WS, HTTP, Kafka, etc). A unified abstraction greatly simplifies the integration and composition of disparate services and data.
Reactive Programming supports more declarative, concise, deterministic ways to express complex, multithreaded algorithms. Remember: only one person TRULY understands how to write safe, concise multithreaded Java code... and it’s NOT you! (It is not me, either!) I don't know who it is. It's better to let the library and framework do the dangerous work of managing concurrency.
Reactive Programming supports services that are more robust. Reactive libraries give us an API protocol to signal that our consumer is overwhelmed, or that it can not handle anymore. Libraries like Project Reactor provide operators to consistently handle errors, back-pressure, and more. The result is safer code with much fewer lines of code.
I believe that all new projects should embrace Reactive Programming, if possible.
So, when I saw that there is a book being written in Chinese to help people understand how to write reactive applications, I was very excited! I hope you'll take the opportunity to read this book, dear reader, and to learn how to work with Reactor and to see how it supports you when building reactive applications with Spring. The opportunities we have today are endless. We have the tools to build almost anything, easily, and to ship that software into production for very cheap. And I am excited to see what you will build with these tools.
Josh Long
Spring 官方布道师
Java Champion 成员
Kotlin GDE 谷歌官方认证开发专家
San Francisco, USA
July 2020
推荐序二
Dear Reader,
Welcome on your journey to building more efficient and resilient applications, welcome to Reactive Programming!
On this path, you will challenge yourself and you will be rewarded with a new mindset that will help you create your next distributed Java services. Interacting with remote services is a common task performed by distributed systems and those interactions take time outside of the calling application control. Multiple reasons are behind this time fluctuation: network latency, the nature of the task run or even a system interruption. At the end of the day, if the calling code needs a result back it will be negatively impacted by that same time because it needs to actively wait for it.
Enter Reactive Programming which gives you the great power of bending space-time to your will! Or sort of... It gives you the ability to remove the negative impact of waiting for anything, so your Thread or CPU is not pinned and can perform other tasks.
Since you can't control how long a remote call will last, you will need to "schedule" the activities your application needs to perform "when" those remote services produce a result. For instance, if your application talks to a remote REST endpoint, it will eventually produce an HTTP response.
"Non Blocking" applications will provide a listener reacting only "when" an underlying network event signals the response back to you. What will do the calling Thread then? It will be able to return to the server worker pool or preparing a next HTTP call, thus increasing service concurrent capacity. It's a scalable design some runtimes have adopted for years, you can implement it with a single thread like Node.JS!
"Non-Blocking" is foundational to Reactive Programming but what does "Reactive" mean anyway? It's maybe not the first time you read the word "Reactive", it has various meanings and it's even mistaken for the popular UI library ReactJS. In this book, when "Reactive" is mentioned, it will always refer to the "reactive-streams" specification which is a clear documented definition adopted by major libraries. "Reactive Streams" defines how an arbitrary "producer" can interact with one or more "consumers" in a Reactive way. Once implemented, the contract offers two key qualities designed to help developers build 100% non-blocking applications: Error Isolation and Flow Control. The former quality contributes to a greater resiliency and availability, producers errors must not interrupt the application, and instead they will forward errors to registered listeners. The latter quality means that producers can't produce more data than consumers are able to consume at any given time. This rule is also known as "backpressure" and it is designed to avoid "unbounded buffers" which has resources consequences on the application host. It helps that one of the major adopters of "Reactive Streams" is the Spring Reactive stack itself including Spring WebFlux and Project Reactor. They do a great job at hiding away a lot of the technical details from the specification I've briefly mentioned in this intro. They provide rich APIs to build reactive flows and help you focus on the "what" and not the "how".
In fact, there are various elements in these libraries designed to ease your first experience with Reactive Programming. First and foremost, Spring can become as much reactive as you need: You can start developing on top of a well-known programming model, Spring MVC, running on Tomcat and you can selectively introduce the modern reactive "WebClient" coming with Spring WebFlux. You can also start returning Project Reactor reactive types Flux and Mono in your Spring MVC controllers the same way you can return CompletableFuture. Ultimately you can just swap your container and start running on top of Netty or Tomcat reactive bridge. Spring conventions such as annotations also matter and most Java developers have learned them for sometimes many years! For instance, @RestController works in both Spring MVC and WebFlux as one could expect. Learning Reactive Programming with Spring is intended to feel like you are learning at home, in a familiar setup.
In this book, you will work with the Spring Reactive stack. I highly recommend you pair this learning opportunity with a good use case that could benefit from going Reactive. For instance, an application depending on a remote service, or an application on the edge of your system serving as a port of entry for many concurrent users.
Learning a new mindset is never easy but it is highly rewarding. Many of the lessons Reactive programming offers apply to all modern software engineering. I think the greatest of these lessons is that it always pays off to be ready with a plan when a component outside your control does not work as you expect.
Good luck!
Stephane Maldini
Netflix 高级软件工程师
Spring Reactor 项目创始人
Reactor-Netty 项目负责人
Spring Framework 项目贡献者
目录
第1章 响应式编程概述 1
1.1 并发与并行的关系 1
1.2 如何理解响应式编程中的背压 2
1.3 源码接口设计启示 3
1.4 如何看待众多函数表达式 11
1.5 Reactor与RxJava的对比 12
1.6 小结 14
第2章 对Flux的探索 15
2.1 对Flux.subscribe订阅逻辑的解读 16
2.1.1 对CoreSubscriber的解读 17
2.1.2 对LambdaSubscriber的解读 22
2.1.3 AtomicXxxFieldUpdater的技法应用 24
2.2 用Flux.create创建源 30
2.2.1 FluxCreate细节探索 31
2.2.2 Flux的快速包装方法 36
2.2.3 Reactor 3中的generate方法 38
2.3 蛇行走位的QueueSubscription 43
2.3.1 无界队列SpscLinkedArrayQueue 44
2.3.2 QueueSubscription.requestFusion的催化效应 47
2.4 Mono的二三事 50
2.5 通过BaseSubscriber自定义订阅者 51
2.6 将常见的监听器改造成响应式结构 53
2.7 Flux.push的特殊使用场景及细节探索 56
2.8 对Flux.handle的解读 58
2.9 小结 63
第3章 调度器 64
3.1 深入理解Schedulers.elastic 65
3.1.1 CachedScheduler的启示 66
3.1.2 ElasticScheduler的类定义思路 68
3.1.3 对Schedulers.decorateExecutorService的解读 69
3.1.4 对ElasticScheduler.schedule的解读 70
3.1.5 对ElasticScheduler.DirectScheduleTask的解读 71
3.1.6 对Schedulers.directSchedule的解读 73
3.1.7 对ElasticScheduler.ElasticWorker的解读 74
3.1.8 ElasticScheduler小结 82
3.2 深入解读publishOn 82
3.2.1 publishOn流程概述 82
3.2.2 对FluxPublishOn的解读 85
3.3 深入解读subscribeOn 98
3.4 Flux.parallel&Flowable.parallel的并行玩法 108
3.5 ParallelFlux.runOn&ParallelFlowable.runOn的调度实现 117
3.6 小结 122
第4章 对Reactor操作的解读 123
4.1 filter操作 123
4.2 transform操作 124
4.3 compose与transformDeferred操作 127
4.4 批处理操作 129
4.4.1 buffer操作 130
4.4.2 window 操作 132
4.4.3 groupBy 操作 139
4.5 merge和mergeSequential操作 140
4.6 flatMap和flatMapSequential操作 142
4.7 concatMap操作 144
4.8 combineLatest操作 145
4.9 ConnectableFlux的二三事及对reactor-bug的分析 146
4.10 小结 158
第5章 对Processor的探索 159
5.1 UnicastProcessor详解 160
5.2 DirectProcessor详解 164
5.3 EmitterProcessor详解 169
5.4 ReplayProcessor详解 174
5.5 小结 188
第6章 TopicProcessor及Reactor中匹配Disruptor的实现代码 189
6.1 初识TopicProcessor 190
6.2 TopicProcessor构造器 195
6.3 对RingBuffer中publish方法的解读 205
6.4 对MultiProducerRingBuffer的解读 208
6.4.1 RingBuffer中的UnsafeSupport 210
6.4.2 RingBuffer中的next与publish操作 216
6.5 TopicProcessor.onSubscribe及类BossEventLoopGroup的设计 221
6.6 TopicProcessor.subscribe及类WorkerEventLoopGroup的设计 225
6.7 小结 241
第7章 对WorkQueueProcessor的解读 242
7.1 WorkQueueProcessor的requestTask 244
7.2 WorkQueueProcessor的subscribe 247
7.3 冷热数据源的区别 251
7.4 实例详解 252
7.5 小结 255
第8章 Reactor中特供的Context 256
8.1 Context的设计缘由 256
8.2 对Context的解读 258
8.3 小结 265
第9章 Reactor中的测试 267
9.1 StepVerifier测试源码解析 267
9.1.1 接口定义 267
9.1.2 接口实现 269
9.1.3 验证 274
9.2 StepVerifier测试应用 275
9.3 操作时间测试 278
9.4 使用StepVerifier进行后置验证 286
9.5 关于Context的测试 289
9.6 使用TestPublisher对自定义中间操作进行测试 296
9.7 使用PublisherProbe检查执行路径 305
9.8 小结 310
第10章 Reactor中的调试 311
10.1 启用调试模式 311
10.2 在调试模式下读取堆栈跟踪信息 315
10.3 通过checkpoint方式进行调试 325
10.4 记录订阅关系下与操作流程相关的日志 326
10.5 小结 326
我力荐作者的“Java编程方法论系列丛书”,因为它们不仅可以帮我们认识到响应式编程的本质原理,同时也兼顾了我们常用的Spring、Netty、WebFlux等框架内容,可以很好地帮助我们将理论与实战联系起来,便于理解与学习。对于响应式编程这种在国外已经非常流行,而在国内还处于萌芽状态的编程理念,如果你也跟我们一样认可这个方向,何不跟随着作者,一起学习它、使用它,为你信仰的技术布道,让身边的技术人都能为之收益?岂不快哉?
—— 《Spring Cloud微服务实战》作者 翟永超
知秋是一个非常乐于分享知识和为别人解答困惑的人。这本关于响应式Reactor的著作是他反复校对并认真打磨的精华之作。写书殊为不易,分享精神更是难能可贵,他能把自己积累的Reactor技术经验总结成Java编程方法论并出版成书是一件非常了不起的事情。我相信这本书不仅会让读者对响应式编程等核心知识有深入理解和技术成长,也会让读者对Java编程方法论有自我思考。
—— 《高可用可伸缩微服务架构》联合作者,公众号“服务端思维”作者 梁桂钊
知秋是一个非常有想法的人,也是中国响应式编程的先行者,他积极联合Reactor的爱好者一起推动着响应式编程在国内的普及。从本书前作讲解响应式RxJava,到本书讲解Reactor,“Java编程方法论系列丛书”深入源码剖析、分享实战经验,为我们在响应式编程的学习道路上提供了非常好的参考资料,能够给我们带来更多响应式编程的完美体验。
—— 海康威视 技术研发专家 方志斌
知秋在响应式编程方面的认知及落地能力,得到了国内业界人士的广泛认可,他出品的教学视频也得到了国外专家们的肯定及推广,他是国内名副其实的响应式编程和NIO领域的专家。“Java编程方法论系列丛书”的出现可谓是及时雨,对有相关学习、工作需求的小伙伴来说,可以给予很好的指导。但要注意的是,该丛书不是泛泛的API讲解,也不是快速入门指南,更不是玄而又玄的概念堆叠,而是成体系的、传授编程思想和技巧的响应式编程学习图书。
—— 国药控股上海生物医药有限公司 架构师 于文龙