实践Spring5 响应式编程框架WebFlux

news2025/1/11 22:49:50

WebFlux 以 Reactor 库为基础, 基于异步和事件驱动,可以让我们在不扩充硬件资源的前提下,提升系统的吞吐量和伸缩性。


一、什么是 Spring WebFlux

了解 WebFlux ,首先了解下什么是 Reactive Streams。Reactive Streams 是 JVM 中面向流的库标准和规范:

处理可能无限数量的元素

按顺序处理

组件之间异步传递

强制性非阻塞背压(Backpressure)

Backpressure(背压)

背压是一种常用策略,使得发布者拥有无限制的缓冲区存储元素,用于确保发布者发布元素太快时,不会去压制订阅者。

Reactive Streams(响应式流)

一般由以下组成:

  • 发布者:发布元素到订阅者

  • 订阅者:消费元素

  • 订阅:在发布者中,订阅被创建时,将与订阅者共享

  • 处理器:发布者与订阅者之间处理数据

响应式编程

有了 Reactive Streams 这种标准和规范,利用规范可以进行响应式编程。那再了解下什么是 Reactive programming 响应式编程。响应式编程是基于异步和事件驱动的非阻塞程序,只是垂直通过在 JVM 内启动少量线程扩展,而不是水平通过集群扩展。这就是一个编程范例,具体项目中如何体现呢?

响应式项目编程实战中,通过基于 Reactive Streams 规范实现的框架 Reactor 去实战。Reactor 一般提供两种响应式 API :

Mono:实现发布者,并返回 0 或 1 个元素

Flux:实现发布者,并返回 N 个元素

Spring Boot Webflux 就是基于 Reactor 实现的。Spring Boot 2.0 包括一个新的 spring-webflux 模块。该模块包含对响应式 HTTP 和 WebSocket 客户端的支持,以及对 REST,HTML 和 WebSocket 交互等程序的支持。一般来说,Spring MVC 用于同步处理,Spring Webflux 用于异步处理。

Spring Boot Webflux 有两种编程模型实现,一种类似 Spring MVC 注解方式,另一种是使用其功能性端点方式。

下图截自 Spring Boot 官方网站:

结合上图,在了解 Spring WebFlux 之前,我们先来对比说说什么是 Spring MVC,这更有益我们去理解 WebFlux,图右边对 Spring MVC 的定义,原文如下:

Spring MVC is built on the Servlet API and uses a synchronous blocking I/O architecture whth a one-request-per-thread model.

翻译一下,意思如下:

Spring MVC 构建于 Servlet API 之上,使用的是同步阻塞式 I/O 模型,什么是同步阻塞式 I/O 模型呢?就是说,每一个请求对应一个线程去处理。

了解了 Spring MVC 之后,再来说说 Spring WebFlux:

上图左边,官方给出的定义如下:

Spring WebFlux is a non-blocking web framework built from the ground up to take advantage of multi-core, next-generation processors and handle massive numbers of concurrent connections.

翻译一下,内容如下:

Spring WebFlux 是一个异步非阻塞式的 Web 框架,它能够充分利用多核 CPU 的硬件资源去处理大量的并发请求。

二、WebFlux 的优势&提升性能?

WebFlux 内部使用的是响应式编程(Reactive Programming),以 Reactor 库为基础, 基于异步和事件驱动,可以让我们在不扩充硬件资源的前提下,提升系统的吞吐量和伸缩性。

看到这里,你是不是以为 WebFlux 能够使程序运行的更快呢?量化一点,比如说我使用 WebFlux 以后,一个接口的请求响应时间是不是就缩短了呢?

抱歉了,答案是否定的! 以下是官方原话:

Reactive and non-blocking generally do not make applications run faster.

WebFlux 并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性。

三、WebFlux 应用场景

上面说到了, Spring WebFlux 是一个异步非阻塞式的 Web 框架,所以,它特别适合应用在 IO 密集型的服务中,比如微服务网关这样的应用中。

PS: IO 密集型包括:磁盘IO密集型, 网络IO密集型,微服务网关就属于网络 IO 密集型,使用异步非阻塞式编程模型,能够显著地提升网关对下游服务转发的吞吐量。

四、选 WebFlux 还是 Spring MVC?

首先你需要明确一点就是:WebFlux 不是 Spring MVC 的替代方案!,虽然 WebFlux 也可以被运行在 Servlet 容器上(需是 Servlet 3.1+ 以上的容器),但是 WebFlux 主要还是应用在异步非阻塞编程模型,而 Spring MVC 是同步阻塞的,如果你目前在 Spring MVC 框架中大量使用非同步方案,那么,WebFlux 才是你想要的,否则,使用 Spring MVC 才是你的首选。

在微服务架构中,Spring MVC 和 WebFlux 可以混合使用,比如已经提到的,对于那些 IO 密集型服务(如网关),我们就可以使用 WebFlux 来实现。

选 WebFlux 还是 Spring MVC? This is not a problem!

咱不能为了装逼而装逼,为了技术而技术,还要考量到转向非阻塞响应式编程学习曲线是陡峭的,小组成员的学习成本等诸多因素。

总之一句话,在合适的场景中,选型最合适的技术。

五、异同点

从上图中,可以一眼看出 Spring MVC 和 Spring WebFlux 的相同点和不同点:

相同点:

  • 都可以使用 Spring MVC 注解,如 @Controller, 方便我们在两个 Web 框架中自由转换;

  • 均可以使用 Tomcat, Jetty, Undertow Servlet 容器(Servlet 3.1+);

  • ...

注意点:

  • Spring MVC 因为是使用的同步阻塞式,更方便开发人员编写功能代码,Debug 测试等,一般来说,如果 Spring MVC 能够满足的场景,就尽量不要用 WebFlux;

  • WebFlux 默认情况下使用 Netty 作为服务器;

六、简单看看 WebFlux 是如何分发请求的

使用过 Spring MVC 的小伙伴们,应该到知道 Spring MVC 的前端控制器是 DispatcherServlet, 而 WebFlux 是 DispatcherHandler,它实现了 WebHandler 接口:

来看看 DispatcherHandler类中处理请求的 handle 方法:

①: ServerWebExchange 对象中放置每一次 HTTP 请求响应信息,包括参数等;

②: 判断整个接口映射 mappings 集合是否为空,空则创建一个 Not Found 的错误;

③: 根据具体的请求地址获取对应的 handlerMapping;

④: 调用具体业务方法,也就是我们定义的接口方法;

⑤: 处理返回的结果;

七、快速入门

7.1 start.spring.io 在线生成

Spring 官方提供了名为 Spring Initializr 的网站,去引导你快速生成 Spring Boot 应用。网站地址为:https://start.spring.io,操作步骤如下:

第一步,选择 Maven 或者 Gradle 构建工具,开发语言 Java 、Kotlin 或者 Groovy,最后确定 Spring Boot 版本号。这里默认选择 Maven 构建工具、Java 开发语言和 Spring Boot 2.0.1。

第二步,输入 Maven 工程信息,即项目组 groupId 和名字 artifactId。这里对应 Maven 信息为:

groupId:springboot

artifactId:sspringboot-webflux-1-quickstart

这里默认版本号 version 为 0.0.1-SNAPSHOT 。三个属性在 Maven 依赖仓库是唯一标识的。

7.2 配置 POM 依赖

检查工程 POM 文件中,是否配置了 spring-boot-starter-webflux 依赖。如果是上面自动生成的,配置如下:

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-webflux</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

<dependency>

<groupId>io.projectreactor</groupId>

<artifactId>reactor-test</artifactId>

<scope>test</scope>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>

7.3 编写处理器类 Handler

import org.springframework.http.MediaType;

import org.springframework.stereotype.Component;

import org.springframework.web.reactive.function.BodyInserters;

import org.springframework.web.reactive.function.server.ServerRequest;

import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;

@Component

public class CityHandler {

public Mono<ServerResponse> helloCity(ServerRequest request) {

return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)

.body(BodyInserters.fromObject("Hello, City!"));

}

}

ServerResponse 是对响应的封装,可以设置响应状态,响应头,响应正文。比如 ok 代表的是 200 响应码、MediaType 枚举是代表这文本内容类型、返回的是 String 的对象。

这里用 Mono 作为返回对象,是因为返回包含了一个 ServerResponse 对象,而不是多个元素。

7.4 编写路由器类 Router

import org.spring.springboot.handler.CityHandler;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.http.MediaType;

import org.springframework.web.reactive.function.server.RequestPredicates;

import org.springframework.web.reactive.function.server.RouterFunction;

import org.springframework.web.reactive.function.server.RouterFunctions;

import org.springframework.web.reactive.function.server.ServerResponse;

@Configuration

public class CityRouter {

@Bean

public RouterFunction<ServerResponse> routeCity(CityHandler cityHandler) {

return RouterFunctions

.route(RequestPredicates.GET("/hello")

.and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),

cityHandler::helloCity);

}

}

RouterFunctions 对请求路由处理类,即将请求路由到处理器。这里将一个 GET 请求 /hello 路由到处理器 cityHandler 的 helloCity 方法上。跟 Spring MVC 模式下的 HandleMapping 的作用类似。

RouterFunctions.route(RequestPredicate, HandlerFunction) 方法,对应的入参是请求参数和处理函数,如果请求匹配,就调用对应的处理器函数。

这里一个简单的服务就写好了,下面怎么运行该服务。

7.5 运行工程

在 IDEA 中执行 Application 类启动,任意正常模式或者 Debug 模式。可以在控制台看到成功运行的输出, 可以看到确实是netty启动的,可以直接访问/hello端点了 :

... 省略

2018-04-10 08:43:39.932 INFO 2052 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext : Started HttpServer on /0:0:0:0:0:0:0:0:8080

2018-04-10 08:43:39.935 INFO 2052 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080

2018-04-10 08:43:39.960 INFO 2052 --- [ main] org.spring.springboot.Application : Started Application in 6.547 seconds (JVM running for 9.851)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/384924.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文推荐:ScoreGrad,基于能量模型的时间序列预测

能量模型&#xff08;Energy-based model&#xff09;是一种以自监督方式执行的生成式模型&#xff0c;近年来受到了很多关注。本文将介绍ScoreGrad&#xff1a;基于连续能量生成模型的多变量概率时间序列预测。如果你对时间序列预测感兴趣&#xff0c;推荐继续阅读本文。 为什…

Qt实现系统桌面目录下文件搜索的GUI:功能一:文件查找与现实

⭐️我叫恒心&#xff0c;一名喜欢书写博客的研究生在读生。 原创不易~转载麻烦注明出处&#xff0c;并告知作者&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 这是一篇近期会不断更新的博客欧~~~ 有什么问题的小伙伴 欢迎留言提问欧。 功能点一&#xff1a;文件查找与…

《MongoDB入门教程》第27篇 创建索引

本文将会介绍 MongoDB 中的索引概念&#xff0c;以及如何利用 createIndex() 方法创建索引。 索引简介 假设存在一本包含介绍各种电影的图书。 如果想要查找一部名为“Pirates of Silicon Valley”的电影&#xff0c;我们需要翻阅每一页&#xff0c;直到发现该电影的介绍为止…

从ChatGPT的技术发展角度解析未来智能化的发展方向

ChatGPT 由人工智能研究实验室 OpenAI 于 2022年11 月 30 日推出。在推出时就带来不小的震动&#xff0c;但真正点燃全民热潮的是&#xff0c;应该是从今年的二月初算起&#xff0c;是全网全平台涵盖各行业领域的舆论盛况。 本文就以ChatGPT为切入点&#xff0c;从技术发展角度…

MQTT协议分析

目录 一、前言 二、MQTT协议概述 概念 基本原理 MQTT协议的结构 MQTT的QoS机制 QoS 0&#xff1a;最多一次传输 QoS 1&#xff1a;至少一次传输 QoS 2&#xff1a;恰好一次传输 三、MQTT的应用场景 四、MQTT的优点和缺点 五、MQTT协议的实现 六、实战体验MQTT …

自己动手写编译器:DFA状态机最小化算法

上一节我们完成了从NFA到DFA的状态机转换&#xff0c;有个问题是状态机并非处于最有状态&#xff1a; 在上图的状态机中&#xff0c;状态6和7其实可以合成一个状态点&#xff0c;本节我们看看如何将这类节点进行合并&#xff0c;使得状态机处于最精简状态(状态4也是终结点&…

KDZD土壤电阻率测试仪

一、简介 KDZD土壤电阻率测试仪专为现场测量接地电阻、土壤电阻率、接地电压、交流电压而精心设计制造的&#xff0c;采用新数字及微处理技术&#xff0c;精密4线法、3线法和简易2线法测量接地电阻&#xff0c;导入FFT(快速傅立叶变换)技术、AFC(自动频率控制)技术&#xff0c;…

基于树莓派4B设计的音视频播放器(从0开始)

一、前言 【1】功能总结 选择树莓派设计一款家庭影院系统,可以播放本地视频、网络视频直播、游戏直播、娱乐直播、本地音乐、网络音乐,当做FM网络收音机。 软件采用Qt设计、播放器引擎采用ffmpeg。 当前的硬件选择的是树莓派4B,烧写官方系统,完成最终的开发。 本篇文章主…

Qt QtCreator 安卓开发环境搭建

踩坑 我的qt是使用在线安装工具安装的&#xff0c;Qt版本使用的是5.15.2&#xff0c;QtCreator版本9.0.2 在网上很多教程都是如下步骤 1.安装qt 2.安装jdk 3.安装android-sdk 4.安装android-ndk 5.配置android设置 例如&#xff1a; https://blog.csdn.net/weixin_51363326/…

【p2p】专利:P2p网络中数据传输的方法、电子设备、装置、网络架构

基于混合CDN的低延时直播P2P技术实践 huya 大佬们的讲座。 而且发表了很多专利: 2018年的,点击直接阅读。 本文是学习笔记 本申请公开了P2P网络中数据传输的方法、电子设备、装置、网络架构,该方法包括步骤:接收服务器发送的数据包,所述数据包由共享资源拆分而成,并由服务…

金山轻维表项目进展自动通知

项目经理作为项目全局把控者&#xff0c;经常要和时间“赛跑”。需要实时了解到目前进展如何&#xff0c;跟进人是那些&#xff1f;哪些事项还未完成&#xff1f;项目整体会不会逾期&#xff1f;特别是在一些大型公司中&#xff0c;优秀的项目经理已经学会使用金山轻维表做项目…

05 Android基础--内部存储与外部存储

05 Android基础--内部存储与外部存储什么是内部存储&#xff0c;什么是外部存储&#xff1f;内部存储与外部存储的代码示例什么是内部存储&#xff0c;什么是外部存储&#xff1f; 1.内部存储与外部存储的存储介质&#xff1a; 内部存储的介质&#xff1a;RAM(内存) 内部ROM …

【连接池】什么是HikariCP?HikariCP 解决了哪些问题?为什么要使用 HikariCP?

文章目录什么是连接池什么是HikariCPHikariCP 解决了哪些问题&#xff1f;为什么要使用 HikariCP&#xff1f;HikariCP 的使用Maven支持数据库什么是连接池 数据库连接池负责分配、管理和释放数据库的连接。 数据库连接复用&#xff1a;重复使用现有的数据库长连接&#xff0…

PayPal轮询收款的那些事儿

想必做跨境电商独立站的小伙伴&#xff0c;对于PayPal是再熟悉不过了&#xff0c;PayPal是一个跨国际贸易的支付平台&#xff0c;对于做独立站的朋友来说跨境收款绝大部分都是依赖PayPal以及Stripe条纹了。简单来说PayPal跟国内的支付宝有点类似&#xff0c;但是PayPal它是跨国…

攒了一冬的甜,米易枇杷借力新电商走出川西大山

“绿暗初迎夏&#xff0c;红残不及春。魏花非老伴&#xff0c;卢橘是乡人。”苏轼文中的卢橘&#xff0c;就是枇杷&#xff0c;在苏轼看来&#xff0c;相较于姚黄魏紫&#xff0c;来自故乡四川的枇杷更为亲近。 四川省攀枝花市米易县是全国枇杷早熟产区之一&#xff0c;得益于…

【存储】RAID2.0+、多路径技术、磁盘可靠性技术

RAID2.0RAID 2.0技术RAID技术发展RAID 2.0软件逻辑对象RAID 2.0基本原理硬盘域Storage Pool & TierDisk Group&#xff08;DG&#xff09;LD&#xff08;逻辑磁盘&#xff09;Chunk&#xff08;CK&#xff09;Chunk Group&#xff08;CKG&#xff09;ExtentGrainVolume &am…

米尔Zynq 7000系列单板的FPGA农业生产识别系统

随着农业生产模式和视觉技术的发展&#xff0c;农业采摘机器人的应用已逐渐成为了智慧农业的新趋势&#xff0c;通过机器视觉技术对农作物进行自动检测和识别已成为采摘机器人设计的关键技术之一&#xff0c;这决定了机器人的采摘效果和农场的经济效率。目前市面上最常见的是基…

MATLAB-Scatter3-三维散点图投影至XYZ三个平面

MATLAB-Scatter3函数可以绘制立体的三维散点图&#xff0c;但有时候需要在该立体图中分析X-Y-Z三者的关系&#xff0c;即1副图呈现出4个信息&#xff0c;XYZ综合信息、XY信息、XZ信息、YZ信息。现有的Scatter3无法实现该功能&#xff0c;本文可实现Scatter3三维立体散点图在三个…

纯手动搭建大数据集群架构_记录011_搭建Nifi_安装部署_搭建集群---大数据之Hadoop3.x工作笔记0172

可以看到左侧,把nifi安装包先上传到服务器,然后,去解压,一样放到opt/software目录,然后解压到/opt/module目录 然后去修改这个配置文件nifi.properties,然后 然后nifi.web.http.port=58080 这里只把 nifi.web.http.port=8080 这个端口改成 58080就可以了. 然后我们进入nifi的bi…

《计算机系统基础》——数据的表示

文章目录《计算机系统基础》——数据的表示移码整数无符号整数 (Unsigned integer)带符号整数&#xff08;Signed integer&#xff09;测试代码浮点数表示范围IEEE 754标准例子规格化数0∞/-∞非数非规格数《计算机系统基础》——数据的表示 移码 &#x1f680;&#x1f680;…