Spring-WebFlux从入门到入坑
初识Spring WebFlux
官网地址:https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html
什么是WebFlux
Spring WebFlux 是spring5提出的一种新的开发web 的技术栈,它是完全无阻塞的,支持 Reactive Streams背压,可以运行在Netty、 Servlet 3.1+ 容器等服务器上,可以支持非常高的并发量。听了这个解释之后,有一种听君一席话,如听一席话的感觉,不要着急,要想学废WebFlux不是一个概念就能理解的,等学完了整篇文章,再回来看这句话,就会通畅多了。。。【手动狗头🐶】
下面是官网提供的对比图,SpringMVC和WebFlux不同点主要在于:
- webFlux是一种非阻塞的开发模式,也就是一个线程可以处理更多请求,而传统的MVC是一种同步的阻塞开发模式,一个请求对应容器里面的一个线程
- 运行环境的不同,SpringMVC是基于Servlet API,所以必须要运行组servlet容器上面,而WebFlux是基于响应式流(Reactive Streams),可以运行在 Servlet 3.1+ 容器(支持异步servlet的容器),或者运行在netty上面(Spring默认容器)
- 数据库:目前关系型数据库都是不支持这种响应式的,比如:Mysql,Oracle这种基于JDBC的数据库,这里为什么不支持关系型数据库是因为JDBC会阻塞线程
- 所以WebFlux 最好的应用场景是系统之间调用

优势
最主要的优势就是提高吞吐量,也就是提高并发量。当我们业务系统的并发量逐渐增大时,我们就要想办法提高系统的并发量,提高并发量的方式主要有两种:一种叫水平扩展,一种叫垂直扩展,简单举例来说,水平扩展就是加人,垂直扩展就是加班
- 水平扩展:增加节点,也就是加机器,增加成本,加钱就能解决
- 垂直扩展:线程还是那么多线程,但是要处理更加多的请求,也就是WebFlux的典型应用
如何学习WebFlux
- 先从JDK8的 lambda表达式和Stream开始学习 ,学习函数式编程的思想
- 学习JDK9的Reactive Streams,了解背压和背压的实现
- 前面两个学完之后,我们就很容易掌握WebFlux的基石 ,也就是Reactor框架,从而掌握WebFlux的技术重点
- 而gateWay就是WebFlux最成功的实现

学习建议
- 我们在学习一个知识点的时候,一定要把这个知识点的前置知识及原理学明白,不要让我们的技术出现技术断层,往往遇到解决不了的问题都是因为技术断层导致的
- 有一定自学和动手能力:要向应用于实际开发工作中,一定要自己写代码勤加练习
- 中高级程序员/架构师:不适合初级程序员,因为很多概念比较抽象
- 提高自己技术功底,提高设计能力的同学:学习WebFlux设计模式以及高性能原因,借鉴它的设计思想和设计理念,提升我们在开发中的程序设计能力
Spring WebFlux前置知识
lambda
Lambda 表达式(lambda expression)是一个匿名函数,
Jdk8自带的函数式接口:

注:上图思维导图分享链接 → 点我打开
Stream流
Stream是一个高级的迭代器,它不是一个数据结构,也不是一个集合,不会存放数据,它关注的是怎么样把数据高效处理,可以理解为把制定数据在流水线中处理,在流水线的开始输入数据,在流水线的尾端得到结果,也就是流水线式处理思想

注: 上图思维导图分享 → 点我打开
函数式编程
函数式编程,是一种相对于命令式编程的一种编程范式,他不是一种具体的技术,而是一种方法论,是一种关于如何搭建应用程序的方法论,这个概念有点抽象,不太好理解,其实网上也没有一个清晰的概念,我的理解就是我们能熟练使用Stream流Api和Lambda表达式,有流相关的一种思想,就可以说我们会用函数式编程了。下面对比一下函数式编程和命令式编程的主要差异
- 命令式编程里面我们关注的是怎么样做
- 函数式编程里面我们关注的是做什么,我们只需要关注实现什么样的功能,而不需要关注实现的细节
- Python代码中基本上每一行代码都可以写成函数式编程,这依赖于Python的语法结构和强大的第三方库函数的支持,这也奠定了Python在敏捷开发快速迭代中的至高地位。java程序员如何快速学习上手Python?→ 点我有彩蛋
响应式编程
响应式编程也有人叫反应式编程, Reactive Programming(反应式编程),是一种高性能应用的编程方式。其最早是由微软提出并引入到 .NET 平台中,随后 ES6 也引入了类似的技术。在 Java 平台上,较早采用反应式编程技术的是 Netflix 公司开源的 RxJava 框架。现在大家比较熟知的Hystrix 就是以RxJava 为基础开发的。是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似”=B1+C1”的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。
最近几年,随着 Node.js、Golang等新技术、新语言的出现,Java在服务器端开发语言老大的地位受到了不小的挑战。虽然,Java 的市场份额依旧很大,短时间内也不会改变,但 Java 社区对于挑战也并没有无动于衷。相反,Java 社区积极应对这些挑战,不断提高自身应对高并发服务器端开发场景的能力。为了应对高并发的服务器端开发,在2009年的时候,微软提出了一个更优雅地实现异步编程的方式 —— Reactive Programming,中文称反应式编程。随后,其它技术也迅速地跟上了脚步,像 ES6 通过 Promise引入了类似的异步编程方式。Java 社区也没有落后很多,Netflix 和 TypeSafe 公司提供了 RxJava和Akka Stream技术,让 Java平台也有了能够实现响应式编程的框架。
Reactive Streams
Reactive Streams是JDK9引入的一套标准,这套标准是有大名鼎鼎的Doug Lea 引入进来的,秉承着苟蛋出品,必是精品的学习原则,Reactive Streams 今后将成为所有java中高级程序员的必修课程,再此我大胆预测,不出五年Reactive Streams将占领各大面试题榜首,成为如今多线程一样的热门面试题目,中国人不骗中国人,我李苟蛋的这个flag今天就在这立下了,5年之后它不火,你来打我🐶。铺垫结束,下面来介绍一下Reactive Streams的基本原理,它是一套基于发布订阅模式的数据处理的规范,在JDK里面真正的叫法应该叫flow API(java.util.concurrent.Flow),它跟之前的Stream流编程没有太大关系,最起码在代码层面没有任何耦合。它引入的背压的概念,什么是背压呢?说白了就是一个交互,也就是一个反馈,是订阅者和发布者之间的一个交互,订阅者可以告诉发布者我需要多少数据,处理完了再去发布者拿数据,数据没处理完,就不要给我数据,这样就可以起到一个调节数据流量的作用。可以避免发布者产生过多数据导致数据大量积压,也避免了把订阅者压垮。
下图为JDK9 Reactive Streams 中有四大接口

示例代码如下:

代码示例订阅者中的 this.subscription.request(1); 就是响应式的关键,订阅者在onNext方法接收发布者发布的数据后,进行业务处理,处理完成之后调用this.subscription.request() 方法向发布者再请求一条数据。
1 | public class FlowDemo01 { |
这里思考一个问题,我们说响应式流里面最关键的就是一个反馈,订阅者可以通过这个反馈来调节生产者发送数据的速度,它究竟是怎么让我们发布者生产数据的速度慢下来的呢?
- 关键点在于发布者这里面的publisher.submit(i); 方法实际上是个阻塞方法,发布者生产的数据会放到Subscription的缓冲器中,缓冲区的默认大小是32,最大缓冲区大小是256。
- 当发布者生产的数据把Subscription的缓冲池放满了,那么发布者生产数据这件事就会停下来,等待订阅者处理完数据之后缓冲池有位置了再继续生产下一条数据

Reactor
前言
其实,在更早之前,像 Mina 和 Netty 这样的 NIO 框架其实也能搞定高并发的服务器端开发任务,但这样的技术相对来说只是少数高级开发人员手中的工具。对于更多的普通开发者来说,难度显得大了些,所以不容易普及。到了2017年,虽然已经有不少公司在实践响应式编程。但整体来说,应用范围依旧不大。原因在于缺少简单易用的技术将响应式编程推广普及,并同诸如 MVC 框架、HTTP 客户端、数据库技术等整合。终于,在2017年9月28日,解决上面问题的利器浮出水面 —— Spring 5 正式发布。Spring 5 其最大的意义就是能将响应式编程技术的普及向前推进一大步。而作为在背后支持 Spring 5 响应式编程的框架 Reactor,也相应的发布了 3.1.0 版本。
在 Java 平台上,Netflix(开发了 RxJava)、TypeSafe(开发了 Scala、Akka)、Pivatol(开发了 Spring、Reactor)共同制定了一个被称为 Reactive Streams 项目(规范),用于制定反应式编程相关的规范以及接口。其主要的接口有这三个:
- Publisher
- Subscriber
- Subcription
反应式编程其实并不神秘,通过与我们熟悉的迭代器模式对比便可了解其基本思想:
event(事件) | Iterable (pull)迭代器 | Subscriber (push)订阅者 |
---|---|---|
retrieve data:检索数据 | T next() | onNext(T) |
discover error | throws Exception | onError(Exception) |
complete | !hasNext() | onCompleted() |
表格的中的 Subscriber 那一列便代表反应式编程的 API 使用方式。可见,它就是常见的观察者模式的一种延伸。如果将迭代器看作是拉模式,那观测者模式便是推模式。被订阅者(Publisher)主动的推送数据给订阅者(Subscriber),触发 onNext
方法。异常和完成时触发另外两个方法。如果 Publisher 发布消息太快了,超过了 Subscriber 的处理速度,那怎么办。这就是 Backpressure(背压) 的由来,Reactive Programming 框架需要提供机制,使得 Subscriber 能够控制消费消息的速度。
Reactor 的主要模块
Reactor 框架主要有两个主要的模块:reactor-core 和 reactor-ipc。前者主要负责 Reactive Programming 相关的核心 API 的实现,后者负责高性能网络通信的实现,目前是基于 Netty 实现的。
Reactor 的主要类
- Reactor 有两个核心类,Mono 和 Flux,这两个类实现接口 Publisher,提供丰富操作符。Flux 代表 N 个元素的发布者;Mono 代表 0 或者 1 个元素的发布者。
- Flux 和 Mono 都是数据流的发布者,使用 Flux 和 Mono 都可以发出三种数据信号: 元素值,错误信号,完成信号,错误信号和完成信号都代表终止信号,终止信号用于告诉 订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者。
- 说白了Reactor我们就可以理解为: Reactor = jdk8 stream + jdk9 reactive stream
SpringWebflux
上面介绍了响应式编程的一些概念,以及 reactive stream 和 Reactor,现在对三者关系总结一下,其实很简单,Reactive Streams 是规范,Reactor 实现了 Reactive Streams。WebFlux 以 Reactor 为基础,实现 Web 领域的响应式编程框架。
Webflux对比SpringMvc
- SpringMVC :同步阻塞的方式,基于 SpringMVC+Servlet+Tomcat
- SpringWebflux :异步非阻塞 方式,基于 SpringWebflux+Reactor+Netty
- SpringWebflux 执行过程和 SpringMVC非常相似,可以对比学习
- SpringWebflux 核心控制器 DispatchHandler,实现接口WebHandler
Webflux开发方式
webFlux提供两种开发模式:
- 第一种就是我们熟悉的以前老的SpringMvc的开发模式,使用@Controller,@RequestMapping之类注解
- 第二种Router Functions,是一种比较类似于函数式编程风格,简洁灵活

方式一:SpringMvc的开发模式
1 | /** |
方式二:Router Functions
1 | /** |
Webflux成功应用之GateWay
- Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和 Project Reactor等技术。
- Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能, 例如:熔断、限流、重试等
- SpringCloud Gateway 是 Spring Cloud 的一个全新项目,基于 Spring 5.0+Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
- SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 1.x非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。


注:上图思维导图的链接地址→ 点我打开 springcloud技术栈
其他应用Fizz GateWay
总结
函数式编程未来可期
我们思考一个问题,为什么Python可以很容易做到函数式编程呢?其核心在于不需要指定变量类型而可以直接调用方法做数据处理,那我们的java可不可以呢?其实正在往这方向发展,当我们所有处理数据的接口都以流对象为参数的时候,岂不就可以做到这种函数式编程的链式调用了吗?我们从WebFlux的核心处理类 DispatcherHandler 中就可以感受得到,我相信不久将来,这种代码风格将会席卷整个中国互联网行业,而我们的代码可读性也将会更上一层楼,所以小伙伴们抓紧入坑吧。。。ps:吹牛,我是专业的【手动狗头】
尾声
- 要想把Webflux玩得精通还需要大量的学习和实践,建议自己可以用Webflux做一些小的需求,来增加使用熟练度
- 从门之后,建议看一些成熟的开源框架的源码,比如说GateWay,学习大佬们是怎么使用的,本文只能做到抛砖引玉的作用
- 最后,谢谢大家