猜你喜欢
Java编程方法论:响应式RxJava与代码设计实战

Java编程方法论:响应式RxJava与代码设计实战

书籍作者:知秋 ISBN:9787121364174
书籍语言:简体中文 连载状态:全集
电子书格式:pdf,txt,epub,mobi,azw3 下载次数:3353
创建日期:2021-02-14 发布日期:2021-02-14
运行环境:PC/Windows/Linux/Mac/IOS/iPhone/iPad/Kindle/Android/安卓/平板
内容简介

本书对RxJava 2的源码进行了深入解读,让读者可以从设计到实现细节上全面了解它,从而达到不仅会用而且可以进行RxJava 2源码库组件级别的拓展的程度。本书的目的不仅是介绍RxJava 2,而且更希望通过一个成熟、优秀的代码库来向读者展示阅读源码的思路及编程方面的技巧,其中包含了并发编程的实战技巧、数据结构的设计方法、设计模式的使用方法、函数式编程的各种技巧等,希望读者可以深入思考并获得属于自己的一套编程方法论。这也是“Java编程方法论系列丛书”的初衷,授之以鱼不如授之以渔。


作者简介

知秋,本名李飞,长期致力于基础代码库的研发工作,通过博客与视频平台bilibili,结合自己的经验做了大量源码解读的分享。对JDK、Spring、RxJava、Spring Reactor、Netty、Reactor-Netty等有很深刻的研究和独到的见解,并以此打造“Java编程方法论系列丛书”。基于开源精神,与志同道合的伙伴们一起创建了simviso开源分享团队,为开源社区服务。


编辑推荐
适读人群 :本书适合有Java编程基础的中高级Java开发工程师、想要学习代码设计思路与技巧的读者、对响应式编程感兴趣的读者阅读。

1. 本书是作者知秋实践经验的总结,业内专家小马哥、梁桂钊、尹相宇、朱勇铭、芋艿、泥瓦匠等倾情力荐。

2. 知秋是国内为数不多的响应式和NIO方向的专家,本书是讲解响应式技术的书籍,在进行源码导读的同时,也引导读者对代码设计进行思考。

3. 响应式是未来的编程趋势,本书深入解读响应式RxJava 2的源码,从设计到实现细节,帮助读者达到RxJava 2源码库组件级别的拓展。

4. 本书包含大量案例,案例按照功能迭代的方式进行讲解,另外作者还录制了相关视频,可以配合学习。


前言

  前言
  本书是“Java编程方法论系列丛书”的第一本书,“Java编程方法论系列丛书”将我多年的代码经验通过讲述优秀的RxJava 2、Reactor 3、Reactor-Netty与Spring WebFlux等框架库的源码细节展现出来,目的是让大家可以学习一种读源码的方式。也就是说,看源码不仅要看懂它干了什么,而且更应该看相关源码的设计思路以及技巧。这就好比研读一篇好文章一样,要揣摩作者的行文方式。
  与理解代码相比,我更愿意带给大家的是一种生活态度。Java的第一个身份是语言,语言是用于描述我们的思想和生活的,所以带着生活中的理念来读源码,你就会发现情况大为不同:各种编程技巧和实现思路通通摆在了你的眼前。本系列丛书就是从这个角度出发的,所以针对的读者是那些想要提高自己对于基础代码掌控能力的中高级程序员。
  下面具体介绍一下本书内容。本书主要讲解了到底什么是响应式,从代码设计层面将JDK 9+中的Flow API、RxJava 2中关于源的创建,以及调度与背压等相关核心操作娓娓道来,并通过实战案例帮助大家更好地理解和使用相关的API。本书涉及了大量并发编程方面的技巧,以及从基础代码角度介绍了各种接口、设计模式和与之相关的基础知识点,并将它们融会贯通。这就好比我们上学的时候,老师向我们传授基础知识,然后通过习题让我们掌握这些基础知识的运用技巧。本书也遵循了这个思路,同时这也符合我写书的初衷。
  限于篇幅,有些内容没能完全在书中呈现,为了降低图书的阅读理解难度,我专门录制了相关的分享视频,可以更直观地带领大家走进源码世界。视频可以说是图书的有益补充,欢迎大家观看、学习。另外,希望读者通过学习本书了解响应式编程如何带来程序性能的提升以及其正确的使用方式。在录制本系列丛书的另一本书《Java编程方法论:响应式Reactor 3、Reactor-Netty和Spring WebFlux》(后续出版)的相关视频时,使我感到很荣幸的是,视频得到了Spring官方的肯定,并在Spring官方推特和博客上进行了宣传、推广,这增加了我对本系列丛书的信心。
  最后,感谢尹相宇同学,没有你听我啰啰唆唆地讲代码,我估计自己的这份激情难以维持,当然,这本书的顺利出版也离不开你的审阅。另外,需要感谢的还有付睿编辑,她帮助我修正了很多表达细节上的错误。最后,感谢我的家人对我的理解和默默付出。
  知秋(李飞)
  2019年2月15日

  推荐序一
  在Architecture and Design InfoQ Trends Report - January 2019 (2019年1月的InfoQ架构和设计趋势报告)中,响应式编程(Reactive Programming)和函数式编程(Functional Programming)编列在第一季度(Q1)的Early Adopter(早期采纳者)中。尽管这仅是一家之言,但是不少开发人员逐渐意识到响应式之风已然吹起。也许你的生产系统尚未出现响应式的身影,不过你可能听说过Spring WebFlux或Netflix Hystrix等开源框架。笔者曾请教过Pivotal(Spring母公司)的布道师Josh Long :“Spring技术栈未来的重心是否要布局在响应式上?”对方的答复是:“没错,响应式是未来的趋势。”同时,越来越多的开源项目开始签署响应式宣言(The Reactive Manifesto) 并喊出了“Web Are Reactive”的口号。
  或许开源界的种种举动无法说服你向响应式的“港湾”中停靠,不过Java 9中Flow API 的引入,又给业界注入了一剂“强心针”。不难看出,无论是Java API,还是Java框架,均走向了响应式编程模型的道路,这并非一种巧合。
  通常,人们谈到的响应式可与响应式编程画等号,以“非阻塞(Non-Blocking)”和“异步(Asynchronous)”的特性并述,以数据结构与操作相辅相成。响应式编程涉及函数式和并发两种编程模型,前者关注语法特性,后者强调执行效率。简言之,响应式编程的意图在于“Less Code,More Efficient”。除此之外,笔者认为响应式更大的价值在于统一Java并发编程模型,使得同步和异步的实现代码无异,同时做到Java编程风格与其他编程语言更好地融合,或许你已经发现Java与JavaScript在响应式方面并不存在本质区别。纵观Java在响应式编程上的发展,其特性更新真可谓步步为营、如履薄冰。尽管Java线程API Thread与Runnable已具备异步以及非阻塞的能力,然而其同步和异步编程的模式并不统一,并且理解Thread API的细节和管理线程生命周期的成本均由开发人员承受。虽然在Java 5引入J.U.C框架(Java并发框架)之后,ExecutorService的实现减轻了以上负担,但是开发人员仍须关注ExecutorService的实现细节。比如,怎样合理地设置线程池空间及阻塞队列又成为新挑战。为此,Java 7引入了ForkJoinPool API,不过此时的J.U.C框架与响应式理念仍存在距离,即使是线程安全的数据结构也并不具备并行计算的能力(如集合并行排序),同时操作集合的手段也相当贫乏,缺少类似Map/Reduce等的操作。不过这些困难只是暂时的,终究会被Java 8“救赎”。Stream API的出现不仅具备数据操作在串行和并行间自由切换的能力(如sequential()及parallel()方法),而且淡化了并发的特性(如sorted()方法既可以进行传统排序,也可以进行并行排序)。相同的设计哲学也体现在Java响应式实现框架中,如本书中提及的RxJava API io.reactivex.Observable。统一编程模型只是流的设计目标之一,它结合Lambda语法特性,虽然提供了数量可观的操作方法,如flatMap()方法等,但是无论对比RxJava,还是Reactor ,流操作方法却又相形见绌。值得一提的是,这些操作方法在响应式的术语中被称为操作符(Operator)。当然框架内建操作符的多与少,并非判断其是否为响应式实现的依据。其中的决定性因素在于数据必须来自发布端(生产者)的“推送(Push)”,而非消费端的“拉取(Pull)”。显然,流属于消费端已就绪(Ready)的数据集合,并不存在其他数据推送源。不过JVM语言早期的响应式定义处于模糊地带,如RxJava API属于观察者模式(Observer Pattern) 的扩展,而非迭代器模式(Iterator Pattern) 的实现。而Reactor的实现则拥抱响应式流规范 ,该规范中消费端对于数据的操作是被动地处理,而非主动地索取。换言之,数据的到达存在着不确定性 。当推送的数据无法得到消费端的及时响应时,响应式框架必须提供背压(Back Pressure) 实现,确保消费端拥有“拒绝的权力(cancel)”。在此理论基础上,响应式流规范定义了一套抽象的API,作为Java 9中java.util.concurrent.Flow API的顶层设计。不过关于操作符的部分,该规范似乎不太关心,这也是RxJava和Reactor均称自身为响应式扩展框架的原因,同时两者在API级别提供了多种调度器(Scheduler) 实现,可适配不同并发场景。尽管响应式定义在不同的阵营之间存在差异,但援引本人在《Reactive Programming:一种技术,各自表述》 一文中的总结:
  Reactive Programming作为观察者(Observer)模式的延伸,不同于传统的命令编程(Imperative Programming)同步拉取数据的方式,如迭代器模式(Iterator),而是采用数据发布者同步或异步地推送到数据流(Data Stream)的方案。当该数据流(Data Stream)的订阅者监听到变化传播时,立即做出响应动作。在实现层面上,响应式编程可结合函数式编程简化面向对象语言语法的臃肿性,屏蔽并发实现的复杂细节,提供数据流的有序操作,从而达到提升代码的可读性以及减少Bug出现的目的。同时,响应式编程结合背压(Back Pressure)的技术解决了发布端生成数据的速度高于订阅端消费数据的速度的问题。
  不难看出,响应式是一门综合的编程艺术,在实现框架的“加持”下,相同的代码逻辑可实现同步与异步非阻塞功能,从而达到提升应用整体性能的目的。不过现实的情况或许没有那么理想,Spring官方文档在“Web on Reactive Stack”章节中提到,“响应式和非阻塞通常并不会让应用运行得更快”:Reactive and non-blocking generally do not make applications run faster.
  为此,JHipster 给出了一份Spring 5 WebFlux性能测试报告 ,其中一条结论是“响应式应用并没有表现出速度的提升(甚至其速度变得更慢)”:No improvement in speed was observed with our reactive apps (the Gatling results are even slightly worse).
  数月后,看似相反的结论却在DZone 的一篇名为Raw Performance Numbers - Spring Boot 2 Webflux vs. Spring Boot 1 的文章中出现,测试结果是Spring Boot 2 WebFlux在高并发下的响应时间更平稳。实际上,这个测试结果有些“关公战秦琼”的味道,毕竟Spring Boot 2下的WebFlux和Spring Boot 1下的Servlet容器所使用的线程模型是不同的,并且Servlet 3.0的异步以及非阻塞特性默认是关闭的。
  不过以上两篇文章的结论并不矛盾,前者关注响应速度,后者则强调吞吐量,两者都是性能的核心指标。遗憾的是,这两篇文章均未对各自的测试用例做出调优,因此以上结论都存在一定的局限性,这也是笔者对响应式技术能否提升性能提出质疑的地方。
  如果说笔者是国内提出响应式问题的第一人的话,那么知秋 就是国内第一个解决响应式问题的人。作为国内为数不多的响应式以及NIO方面的专家,在技术研究上,他追求格物致知,不轻易忽略技术细节;在知识分享上,他可谓知无不言,言无不尽,不仅在社交群中答疑解惑,而且录制免费视频,发布在B站 以及YouTube频道 上,并得到了Josh Long等“大牛”的推文(Twitter)。或许以上方式还不足以完整地讨论Java响应式技术,因此,知秋选择了漫长而又艰苦的著书之路。尽管他是笔者的朋友,然而“内举不避亲”,笔者郑重地向读者朋友推荐本书。这是中国大陆地区(不含港澳台地区)第一本全面解读Java响应式技术的书籍,作者的技术积累雄厚,书中的知识脉络循序渐进。同时,这也是一本引人深思的书,在进行源码导读的同时,也引导读者对代码设计进行思考。另外,这又是一本知识苦旅的书,因为它的涉及面较广,读者不仅需要具备一定的Java并发以及面向对象设计的基础,而且需要花费较多的时间去反复推敲书中的有关内容。正所谓“夫夷以近,则游者众;险以远,则至者少” ,笔者希望读者在购买本书后,不轻言放弃,当你面临挑战时,那才是成长的开始。同时,笔者也期盼读者将响应式技术付诸实践,提早“触碰”未来。
  小马哥(mercyblitz)
  2019年3月5日
  推荐序二
  有幸与李飞兄相识多年,他严谨的治学态度和认真的工作作风让我敬佩不已。值得一提的是,李飞兄是一个非常乐于分享知识和帮助他人解惑的人。我经常在微信群中看到他热情地帮助他人分析问题并提供解答思路。此外,他晚上还经常开视频来分享自己对Java编程方法论的思考与心得。当然,这些视频是免费、公开的,其中很多内容涉及本书的知识点,可以认为是本书很好的补充。事实上,我也是他的忠实听众之一,所以非常推荐大家在购买本书的同时结合视频一起学习,如此则效果更佳。因此,我对他充沛的精力和满满的分享精神甚是佩服。写书殊为不易,分享精神更是难能可贵,因此,当我得知李飞兄要将他对Java编程和响应式编程的技术经验编写成书的时候,甚是欣喜,因为我相信这本书不仅会给读者带来响应式编程等核心知识的深入理解和技术成长,同时也会让读者对Java编程方法论有自己的思考。
  响应式编程是未来架构的一次升级。事实上,我们业务的主流模式会使用RPC和Spring MVC的同步等待机制,以及通过并行调用缩短平均响应时间,这种做法对性能的提升非常显著。但是,随着业务的复杂演变,可能会出现回调地狱,而且冗余的业务代码和大量的并行代码也会导致程序越来越难以维护。此时,一个新的编程思想——响应式编程——应运而生,它通过避免等待以缩短平均响应时间来保证系统的利用率。在这里,响应式编程的关键元素之一是能够异步执行任务。这种全异步方式的优势在于,可以充分地利用线程的时间片。另外,响应式编程是一种面向数据流和变化传播的编程范式。事实上,它是一种新思路,我们可以认为任何东西都是一个数据流,即“万物皆为流”,因此我们需要面向数据流编程。它并不陌生,可以通过观察者模式来构建。我们可以创建事件流和数据流,然后让观察者/消费者订阅任何需要关心的数据流并执行相关的业务操作。例如,我们经常提到的事件总线,其本质上就是通过异步事件流对监听的事件变化做出响应。响应式编程还有一个很重要的概念——变化传播。例如,输入一个数据流,经过一系列的操作转化成另一个数据流。为了更好地理解这个特性,我们可以把数据流类比成一条河流:它可以被观测、被加工或者被合并成一条新河流。因此,随着响应式编程的发展成熟,如果能把全异步流式的能力引入业务开发中,不仅可以使项目的性能得以提升,而且也可以给项目带来更多的灵活性。
  本书详细介绍了RxJava的源码细节和后端的实战使用方法,不论是刚接触响应式编程的入门读者,还是已经有响应式编程实战经验的进阶读者,阅读本书都会收获颇多。
  梁桂钊
  阿里巴巴Java高级开发工程师
  推荐序三
  响应式编程日益流行,如今Java语言正经历着快速迭代,然而很多Java开发者仍沉浸在Java 7/Java 8的世界。在Java 9发布前飞哥已经开始着手编写本系列丛书的准备工作,目标是让广大开发者能够学习全新的Java语言。如今的Java已经提供了函数式编程支持、模块化的JDK和模块化开发支持、对流式编程友好的G1垃圾回收器、低延迟的ZGC等特性,包含的内容非常丰富。由于计划写的内容很多,飞哥后来索性将响应式编程的部分拆分出来,成为现在我们所看到的这本书。时过境迁,Java语言早已不是被人诟病的臃肿语言,在其之上大量的精妙设计得以实现,事实证明Java拥有独特的魅力和经久不衰的生命力。
  学习响应式编程最重要的是理解它的设计思想,我们不能只将RxJava、Reactor以及Spring WebFlux作为一个工具框架看待,会使用它们并不意味着能够驾驭它们。学习这本书会让你了解响应式编程如何带来程序性能的提升,以及什么是响应式编程的正确使用方式。如果说代码是躯体,那么什么才是灵魂?躯体和灵魂相比,谁又是永生的?本书所讲的不只是具体的使用方法,还会讲解其中的设计思想:从它的源码设计中学习如何设计,通过源码还原其本质。机会总是留给有准备的人,抓住Java的响应式编程趋势,追寻自己所向往的生活。
  在阅读本书的过程中,切忌不可囫囵吞枣。如果读者的基础尚未稳固,建议在阅读时谨慎对待书中的内容。很多小段落不可只理解字面上的描述,在你多次回味并细细揣摩后,便可发现其中的深层次视角。书中内容大多前后关联,因此不推荐跳跃式阅读。
  在阅读本书选取的源码时,切不可一眼过之,因为这些源码多为关键所在。本书拨开“浮云”,在大量的源码中直击要害,帮助读者了解程序的执行方式和设计思路。在阅读本书时,准备好对应的源码是一个聪明的选择。书中的案例均经过精心的设计,从简单使用开始,不断地增添和修改,让读者在学习的过程中不脱离实战,逐步掌握响应式编程。
  响应式编程作为未来编程的趋势,具有异步、非阻塞的特点,它能够支持更大的吞吐量,相较于传统的服务实现方式其占用较少的资源。在学习本书的内容前,希望读者能够对Lambda表达式和Steam(流)有一些了解,不了解也没有关系,本系列丛书中关于JDK的书会在本书之后出版,让大家认识全新的Java。另外,配套视频教程已经准备好,在B站或YouTube上搜索“Java编程方法论”就可以找到它们。
  尹相宇
  格力Java高级工程师


目录

第1章 响应式编程总览(Reactive Programming) 1

1.1 异步编程模式 1

1.1.1 并发 2

1.1.2 并行开发初探 3

1.2 流(Stream) 3

1.3 响应式流(Reactive Stream) 4

1.3.1 响应式流的特性 4

1.3.2 响应式开发的设计原则 5

1.3.3 响应式开发的好处 6

1.4 响应式开发工具库 6

1.4.1 RxJava简介 6

1.4.2 Reactor简介 7

1.4.3 MongoDB简介 8

1.4.4 响应式项目用例 8

1.5 Java 9中的响应式编程 10

1.5.1 响应式编程接口 10

1.5.2 Java 9响应式编程入门Demo 12

1.5.3 SubmissionPublisher类的源码解读 18

1.5.4 响应式编程整合Spring实战案例 23

1.6 小结 29

第2章 在RxJava中创建Observable 30

2.1 响应式编程所涉及的设计模式 30

2.1.1 观察者模式 30

2.1.2 迭代器模式 30

2.2 解读reactivex.Observable 31

2.2.1 从Flow.Publisher到Observable 33

2.2.2 subscribe的二三事 33

2.2.3 create方法的设计思想 36

2.2.4 各式各样的Observable 40

2.2.5 Observable.cache 43

2.2.6 无限流 49

2.2.7 在Observable内处理错误 54

2.2.8 定时控制Observable发送数据 56

2.2.9 Disposable延伸 59

2.2.10 ConnectableObservable解读 67

2.2.11 Observable中的publish.refCount解读 76

2.2.12 RxJava中的Subject解读 79

2.3 小结 89

第3章 RxJava 2中的操作 90

3.1 核心操作 90

3.1.1 使用filter进行条件过滤 90

3.1.2 使用map进行元素转换 96

3.1.3 使用flatMap进行扁平化转换 98

3.1.4 使用scan累加器 112

3.1.5 使用groupBy进行分组 114

3.2 多个Observable的合并操作 122

3.2.1 使用merge对Observable进行合并 122

3.2.2 使用zip方法进行合并 124

3.2.3 combineLatest操作 135

3.2.4 withLatestFrom操作 141

3.2.5 amb操作 142

3.3 高级操作 143

3.3.1 再谈累加器scan 143

3.3.2 聚合操作reduce 144

3.3.3 收集操作collect 146

3.3.4 使用distinct去重 148

3.3.5 使用distinctUntilChanged过滤重复数据 152

3.3.6 其他操作 152

3.3.7 自定义操作 153

3.4 小结 159

第4章 对RxJava 2的设计探索 160

4.1 源的创建设计思路 160

4.2 中间操作的转承 162

4.3 小结 166

第5章 Observable实战 167

5.1 初版架子实现 167

5.1.1 DAO层面的处理工作 167

5.1.2 控制层的响应式实现 172

5.2 基于架子实现一个汇率查询的服务 175

5.3 rxjava-web-spring-boot-starter的抽取设计 179

5.4 ObservableSseEmitter的设计实现 188

5.5 小结 196

第6章 RxJava 2中的多线程操作 197

6.1 初探RxJava并发编程 197

6.2 subscribeOn操作 211

6.3 observeOn操作 216

6.4 unsubscribeOn操作 220

6.5 调度器Scheduler 226

6.5.1 Schedulers.newThread方式 227

6.5.2 Schedulers.io方式 227

6.5.3 Schedulers.computation方式 228

6.5.4 Schedulers.from(Executor executor)自定义方式 228

6.6 小结 230

第7章 Flowable与背压 231

7.1 回顾背压 231

7.2 引入Flowable 233

7.3 探索Flowable.create 234

7.3.1 BackpressureStrategy.BUFFER策略 239

7.3.2 BackpressureStrategy.LATEST策略 246

7.3.3 BackpressureStrategy.DROP策略 249

7.4 将一个Observable转化为一个Flowable 251

7.5 通过onBackpressureXXX操作来实现背压策略 252

7.5.1 onBackPressureBuffer操作 255

7.5.2 onBackpressureLatest与onBackpressureDrop操作 256

7.6 Flowable.generate操作 257

7.7 小结 262

第8章 Flowable实战 263

8.1 使用Flowable封装JDBC 263

8.1.1 封装部分查询逻辑 263

8.1.2 封装update逻辑 265

8.2 结合Spring Web应用使用Flowable 268

8.2.1 接口数据的获取 269

8.2.2 响应式服务的源设计 271

8.3 单元测试 274

8.3.1 使用Mock Service Server进行测试 274

8.3.2 使用@Mock来进行一些服务测试 277

8.4 controller层的实现逻辑改造 279

8.5 小结 282


产品特色