【Spring Boot】响应式编程

响应式编程

  • 1.WebFlux
  • 2.比较 MVC 和 WebFlux
    • 2.1 工作方式
    • 2.2 Spring MVC 与 Spring WebFlux 的区别
    • 2.3 使用 WebFlux 的好处
  • 3.Mono 和 Flux
    • 3.1 Mono 和 Flux 是什么
    • 3.2 Mono 和 Flux 的区别
  • 4.开发 WebFlux 的流程
    • 4.1 注解式开发流程
    • 4.2 响应式开发流程
  • 5.用注解式开发实现 Hello World
    • 5.1 配置 WebFlux 依赖
    • 5.2 编写控制器
  • 6.用响应式开发方式开发 WebFlux
    • 6.1 编写处理器类 Handler
    • 6.2 编写路由器类 Router

1.WebFlux

WebFlux 是从 Spring Framework 5.0 开始引入响应式 Web 框架的。与 Spring MVC 不同,WebFlux 不需要 ServletAPI,在完全异步且无阻塞,并通过 Reactor 项目实现 Reactive Streams 规范。

WebFlux 可以在资源有限的情况下提高 系统的吞吐量和伸缩性(不是提高性能)。这意味着在资源相同的情况下,WebFlux 可以处理更多的请求(不是业务)。

WebFlux 除支持 RESTful Web 服务外,还可以用于提供动态 HTML 内容。

2.比较 MVC 和 WebFlux

Spring MVC 采用命令式编程的方式,代码被一句一句地执行,便于开发者理解与调试代码。WebFlux 则是基于异步响应式编程。

2.1 工作方式

  • MVC:主线程接收到请求(request)→ 准备数据 → 返回数据。整个过程是单线程阻塞的,用户会感觉等待时间长是因为,在结果处理好之后才返回数据给浏览器。因此,如果请求很多,则吞吐量就上不去。
  • WebFlux:主线程接收到请求 → 立刻返回数据与的数的组合(MonoFlux,不是结果) → 开启一个新 Work 线程去做实际的数据准备工作,进行真正的业务操作 → Work 线程完成工作 → 返给用户真实数据(结果)。这种方式给人的感觉是响应时间很短,因为返回的是不变的常数,它不随用户数量的增加而变化。

2.2 Spring MVC 与 Spring WebFlux 的区别

在这里插入图片描述

对比项
Spring MVC
Spring WebFlux
地址(路由)映射@Controller、@RequestMapping 等标准的 Spring MVC 注解(1)Router Functions,提供一套函数式风格的 API,用于创建 Router、Handler 和 Filter
(2)@Controller、@RequestMapping 等标准的 Spring MVC 注解
数据流Servlet APIReactive Streams:一种支持背压(backpressure)的异步数据流处理标准,主流实现有 RxJavaReactor。Spring WebFlux 默认集成的是 Reactor
容器Tomcat、Jetty、UndertowNetty、Tomcat、Jetty、Undertow
I/O 模型同步阻塞的 I/O 模型异步非阻塞的 I/O 模型
吞吐性能
业务处理性能一样一样
支持数据库NoSQL、SQL支持 NoSQL,不支持 MySQL 等关系型数据库
请求和响应HttpServletRequestHttpServletResponseServerRequestServerResponse

2.3 使用 WebFlux 的好处

下面以餐厅 “叫号” 来比喻阻塞式开发与 WebFlux。

假设 “海底捞” 没有叫号机(前台服务员),店里有 200 个餐台供客人进餐,如果此时来了 201 个客人,那么最后一个客人就直接被拒绝服务了。

而现在有叫号机,来了 200 个客人正在用餐,后面再来 100 个客人,叫号机马上给后面的 100 个客人每人一个排队号。这样服务就不阻塞了,每个人都立马得到反馈。来再多的人也能立马给排号,但是进餐依然是阻塞的。

回到程序。我们假设,服务器最大线程资源数为 200 个,当前遇到 200个非常耗时的请求,如果再来 1 个请求时,阻塞式程序就已经处理不了(拒绝服务)了。

而对于 WebFlux,则可以做到立即响应(告诉用户等着),然后将收到的请求转发给 Work 线程去处理。WebFlux 只会对 Work 线程形成阻塞,如果再来请求也可以处理。其主要应用场景是在业务处理较耗时的场景中减少服务器资源的占用,提高并发处理速度。

对 WebFlux 的一个简单的理解就是:你来了,我立马应答你,但是服务需要等待;而不是你来了没人理你,咨询服务半天也回复不了。

结论:MVC 能满足的场景,就不需要改用 WebFlux。WebFlux 和 MVC 可以混合使用。如果开发 I/O 密集型服务,则可以选择用 WebFlux 实现。

如果在 pom.xml 文件中同时引用了 spring-boot-starter-webspring-boot-starter-webflux 依赖,则优先会使用 spring-boot-starter-web。这时,控制台输出的启动日志会提示 “Tomcat started on port(s): 8080 (http) with context path”,而使用 WebFlux 会提示 “Netty started onport(s): 8080”。

3.Mono 和 Flux

3.1 Mono 和 Flux 是什么

Mono 和 Flux 是 Reactor 中的两个基本概念。

  • Mono 和 Flux 属于 事件发布者,为消费者提供订阅接口。当有事件发生时,Mono 或 Flux 会回调消费者的相应方法,然后通知消费者相应的事件。这也是响应式编程模型。
  • Mono 和 Flux 用于处理异步数据流,它不像 MVC 中那样直接返回 String/List,而是将异步数据流包装成 Mono 或 Flux 对象。

3.2 Mono 和 Flux 的区别

  • Flux 可以发送很多 item,并且这些 item 可以经过若干算子(operators)后才被订阅。Mono 只能发送一个 item

  • Mono 主要用于返回单个数据。Flux 用于返回多个数据。如果要根据 id 查询某个 User 对象,则返回的肯定是单个 User,那么需要将其包装成 Mono<User>。若需要获取所有 User(这是一个集合),则需要将这个集合包装成 Flux<User>。这里的单个数据并不是指一个数据,而是指封装好的一个对象。多个数据就是多个对象。

  • Mono 表示包含 0 或 1 个元素的异步序列。在该序列中可以包含 3 种不同类型的消息通知:正常的包含元素的消息序列结束的消息序列出错的消息。当消息通知(正常的包含元素的消息、序列结束的消息、序列出错的消息)产生时,订阅者中有对应的方法 onNext()onComplete()onError() 被调用。

  • Flux 表示的是包含 0 到 N 个元素的异步序列,在该序列中可以包含与 Mono 相同的 3 种类型的消息通知。

  • Flux 和 Mono 之间可以进行转换。对一个 Flux 序列进行计数操作时,得到的结果是 Mono<Long> 对象。把多个 Mono 序列合并在一起,得到的是一个 Flux 对象。

4.开发 WebFlux 的流程

4.1 注解式开发流程

WebFlux 是响应式框架,其中使用的 注解式开发方式 只是 Spring 团队为了更好地迁移而提的。和 MVC 开发模式一样,地址映射也是通过 @RequestMapping 提供的,用 @Controller 或 @RestController 来代替 Handler 类。

4.2 响应式开发流程

(1)创建 Handler 类。这里的 Handler 类相当于 Spring MVC 的 Controller 层中的方法体。在响应式编程中,请求和响应不再是 HttpServletRequest 和 HttpServletResponse,而是变成了 ServerRequest 和 ServerResponse。

(2)配置 RouterFunction。RouterFunction 和注解 @RequestMapping 相似,都用于提供 URL 路径。RouterFunction 的格式也是固定的,第 1 个参数代表 路径,第 2 个参数代表 方法,合起来代表将 URL 映射到方法。

5.用注解式开发实现 Hello World

5.1 配置 WebFlux 依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

5.2 编写控制器

用注解式开发 WebFlux 应用程序与 MVC 的开发方式是一样的。通过注解 @RestController 标注控制器类,通过注解 @GetMapping 指定映射路径。

package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;@RestController
public class HelloWorldController {@GetMapping("/helloworld")public Mono<String> helloworld(){return Mono.just("This is WebFlux demo");}
}

启动工程后,控制台中输出如下:

在这里插入图片描述

可以看到,WebFlux 默认使用的是 Netty 服务器,而不是 MVC 模式下的 Tomcat 服务器。

在这里插入图片描述

6.用响应式开发方式开发 WebFlux

6.1 编写处理器类 Handler

Handler 相当于 MVC 中的 Controller。用于提供实现功能的方法。

package com.example.demo;import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;@Component
public class HelloWorldHandler {public Mono<ServerResponse> sayHelloWorld(ServerRequest serverRequest) {return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).body(Mono.just("This is WebFlux demo"), String.class);}
}

6.2 编写路由器类 Router

package com.example.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;@Configuration
public class Router {@Autowiredprivate HelloWorldHandler helloWorldHandler;@Beanpublic RouterFunction<ServerResponse> getString(){return route(GET("/helloworld"),req->helloWorldHandler.sayHelloWorld(req));}
}

上述代码中,通过 return route(GET("/helloworld"),req->helloWorldHandler.sayHelloWorld(req)); 来指定路由,包含 HTTP 方法和对应的功能方法。

在这里插入图片描述

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

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

相关文章

基于开源ATmega8 无感BLDC程序移植到ATmega328PB

基于开源ATmega8 无感BLDC程序移植到ATmega328PB &#x1f516;基于Atmel Studio 7.0开发环境。&#x1f955;开源原项目资源地址&#xff1a;https://svn.mikrokopter.de/websvn/listing.php?repnameBL-Ctrl&path%2F&&#x1f4cd;原理图和PCB资源 BL-Ctrl v2.0 in E…

Win32 API

个人主页&#xff1a;星纭-CSDN博客 系列文章专栏 : C语言 踏上取经路&#xff0c;比抵达灵山更重要&#xff01;一起努力一起进步&#xff01; 一.Win32 API 1.Win32 API介绍 Windows这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外&#xff0c;它同时也是…

Redis内存回收-内存淘汰策略

LFU的访问次数之所以叫做逻辑访问次数&#xff0c;是因为并不是每次key被访问都计数&#xff0c;而是通过运算&#xff1a; 生成0~1之间的随机数R计算 (旧次数 * lfu_log_factor 1)&#xff0c;记录为P如果 R < P &#xff0c;则计数器 1&#xff0c;且最大不超过255访问…

9.任务调度

一、开启任务调度器 1.函数 vTaskStartScheduler() 函数 vTaskStartScheduler()用于启动任务调度器&#xff0c;任务调度器启动后&#xff0c;FreeRTOS 便会开始 进行任务调度&#xff0c;除非调用函数 xTaskEndScheduler()停止任务调度器&#xff0c;否则不会再返回。函数 vTa…

Centos修改系統語言

一、使用命令行修系统语言 1、显示系统当前语言环 [rootkvm-suma ~]# localectl System Locale: LANGen_US.utf8 VC Keymap: cn X11 Layout: cn 2、查看系统支持字符集 [rootkvm-suma ~]# locale -a 2、设置系统语言环境 [rootkvm-suma ~]# localectl set-locale LANGz…

【GESP试卷】2024年03月Scratch四级试卷

2024年GESP03月认证Scratch四级试卷 分数&#xff1a;100 题数&#xff1a;27 一、单选题(共15题&#xff0c;每题2分&#xff0c;共30分) 010203040506070809101112131415CDBBACBCDCDADBA 1、小杨的父母最近刚刚给他买了一块华为手表&#xff0c;他说手表上跑的是鸿蒙&…

【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【00】补充

持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【00】补充 插件IDEAVsCode MavenvagrantDocker解决MySQL连接慢问题启动&#xff08;自动&#xff09;Docker注意切换到root用户远程访问MySQL MyBatisPlus代码地址参考 插件 IDEA Mybati…

【数据挖掘】四分位数识别数据中的异常值(附代码)

写在前面&#xff1a; 首先感谢兄弟们的订阅&#xff0c;让我有创作的动力&#xff0c;在创作过程我会尽最大能力&#xff0c;保证作品的质量&#xff0c;如果有问题&#xff0c;可以私信我&#xff0c;让我们携手共进&#xff0c;共创辉煌。 路虽远&#xff0c;行则将至&#…

STM32F1之OV7725摄像头

目录 1. 摄像头简介 2. OV7725 摄像头简介 3. OV7725 引脚 4. OV7725 功能框架图 5. SCCB时序 5.1 SCCB 的起始、停止信号及数据有效性 5.2 SCCB 数据读写过程 1. 摄像头简介 在各类信息中&#xff0c;图像含有最丰富的信息&#xff0c;作为机…

SVM原问题与对偶问题

目的&#xff1a;求出我们的f(X)&#xff0c;它代表着我们X映射到多维的情况&#xff0c;能够帮我们在多维中招到超平面进行分类。 1.优化问题&#xff1a; 1.1推荐好书&#xff1a; 1.2 优化理论中的原问题&#xff1a; 原问题和限制条件如下&#xff1a; 这是一个泛化性…

【漏洞复现】英飞达医学影像存档与通信系统 WebJobUpload 任意文件上传漏洞

0x01 产品简介 英飞达医学影像存档与通信系统 Picture Archiving and Communicaton System&#xff0c;它是应用在医院影像科室的系统&#xff0c;主要的任务就是把日常产生的各种医学影像(包括核磁&#xff0c;CT&#xff0c;超声&#xff0c;各种X光机&#xff0c;各种红外仪…

LeetCode - 数组 - 四数之和

题目地址 描述 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#xff09;&#x…

cs与msf权限传递以及mimikatz抓取win2012明文密码

简单的介绍 cs与msf的简单介绍 我查找过资料得出&#xff0c;Cobalt Strike 的前身是 Armitage&#xff0c;而 Armitage 又可以理解为 Metasploit Framework 的图形界面版&#xff0c;因此 Cobalt Strike 与 Metasploit Framework 在很多地方都是兼容的&#xff0c;所以我们便…

人工智能 框架 paddlepaddle 飞桨 使用指南 使用例子 线性回归模型demo 详解

安装过程&使用指南&线性回归模型 使用例子 本来预想 是安装 到 conda 版本的 11.7的 但是电脑没有gpu 所以 安装过程稍有变动,下面简单讲下 conda create -n paddle_env117 python=3.9 由于想安装11.7版本 py 是3.9 所以虚拟环境名称也是 paddle_env117 activa…

下载和安装AD19 - Altium Designer 19.1.9 Build 167

虽然有AD24 的安装资源&#xff0c;但是我比较喜欢19 这个数字[doge] 下载 仍然是从毛子网站源头进货&#xff1a;https://rutracker.net/forum/viewtopic.php?t5754276&#xff0c;网盘: https://pan.baidu.com/s/1ic31N4h7HS2FBu7JFll0YQ?pwdvjum 提取码: vjum 安装 压…

【DevOps】深入了解RabbitMQ:AMQP协议基础、消息队列工作原理和应用场景

目录 一、核心功能 二、优势 三、核心概念 四、工作原理 五、交换机类型 六、消息确认 七、持久性和可靠性 八、插件和扩展 九、集群和镜像队列 十、客户端库 十一、管理界面 十二、应用场景 RabbitMQ是一个基于AMQP协议的消息队列中间件&#xff0c;提供高可用、可…

[MRCTF2020]Xor

32位程序 主要逻辑 flagMSAWB~FXZ:J:tQJ"N bpdd}8g for i in range(len(flag)):print(chr(ord(flag[i])^i),end)

react 权限树形结构实现

项目背景 react ant design 实现效果 1 将后台返回的平铺数据 , 转成树形结构 const [roleId, setRoleId] useState() //存储角色id// 弹权限弹窗const empowerHandle async record > {setRoleId(record.roleId)//获取单独的权限const res1 await getPermission({ role…

力扣96. 不同的二叉搜索树

Problem: 96. 不同的二叉搜索树 文章目录 题目描述思路复杂度Code 题目描述 思路 一个数字做根节点的话可能的结果为&#xff1a;其左边数字做子树的组合数字乘以其右边数字做子树的个数之积 1.创建备忘录memo&#xff1b; 2.递归分别求取当前数字左边和右边数字做子树的数量&…

Vue 中 diff 算法原理

1. Diff 概念 vue 基于虚拟 DOM 做更新 。diff 的核心就是比较两个虚拟节点的差异 。Vue 的 diff 算法是平级比较,不考虑跨级比较的情况。内部采用深度递归的方式 + 双指针的方式进行比较。 2. Vue2 Diff 比较流程. 1.1先比较是否是相同节点 key tag 1.2相同节点比较属性,并…