Spring Boot (十四): 响应式编程以及 Spring Boot Webflux 快速入门
1. 什么是响应式编程
在计算机中,响应式编程或反应式编程(英语:Reactive programming)是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。
例如,在命令式编程环境中,a=b+c 表示将表达式的结果赋给 a,而之后改变 b 或 c 的值不会影响 a 。但在响应式编程中,a 的值会随着 b 或 c 的更新而更新。
响应式编程是基于异步和事件驱动的非阻塞程序,只需要在程序内启动少量线程扩展,而不是水平通过集群扩展。
设想一个场景,从底层数据库驱动,经过持久层、服务层、MVC层中的model,到用户的前端界面的元素,全部都采用声明式的编程范式,从而搭建一条能够传递变化的管道,这样我们只要更新一下数据库中的数据,用户的界面上就相应的发生变化,从而无需前端轮询才能获取到最新的数据。
简单来讲,我们以前写的程序是阻塞式的,当一个请求任务过来时,线程会阻塞,等到这个任务完成后再返回出去。而响应式编程则是一个请求任务过来时,会有其他的线程去做处理,当任务执行结束后再异步的通知回去。
2. 为什么要使用响应式编程
在如今互联网时代的大背景下,Web应用通常要面对高并发、海量数据的挑战,性能从来都是必须要考量的核心因素。
阻塞便是性能杀手之一。
多数人不认为阻塞是一个比较大的问题,至少觉得除了网络I/O之外,读写文件和数据库还是很快的,许多人也一直在写阻塞的代码。
那么 I/O 操作具体有多慢?
2.1 CPU眼中的时间
以下内容来源 https://blog.csdn.net/get_set/article/details/79466402
CPU绝对称得上是“闪电侠”,因为它们做事都有自己的一套时钟。我们故事的主人公是一个主频为2.5GHz的CPU,如果它的世界也有“秒”的概念,并且它的时钟跳一下为一秒,那么在CPU(CPU的一个核心)眼中的时间概念是啥样的呢?
CPU先生所在的组是硬件部计算组。对它来说,与其一起紧密合作的几个小伙伴还能跟的上它的节奏:
- CPU先生很利索,只需要一秒就可以完成一个指令,复杂的动作可能需要多个指令。
- 好在“贴身秘书”一级缓存反应比较快,能够秒懂CPU先生的意思。
- 来自“秘书组”的二级缓存虽然要十几秒才能“get”到CPU先生的点,但也不算太迟钝。
- 和内存组的合作已经习以为常了,跟内存请求的数据通常要4-5分钟才能找到(内存寻址),不过也还好啦,毕竟一级缓存那里能拿到80%想要的数据,其余的二级缓存也能搞定一大部分,不怎么耽误事儿。
CPU先生是典型的工作狂,任务多的时候,通宵达旦也毫无怨言,但是有什么事情让它等,那简直要他命了。恰恰一起共事的其他组(尤其是I/O组的磁盘和网卡)相对来说那效率是低的离谱啊:
- 关于I/O组的同事,CPU先生已经抱怨很久了,每次找SSD要东西,都要花费4-5天才能找到(寻址),等到数据传送过来,几周都过去了。机械磁盘更是过分地离谱,跟他要个数据,竟然要平均花费10个月才能找到,如果要读取1M的数据,竟然要20个月!这种员工怎么还不下岗?!
- 关于网卡,CPU先生知道它们也尽力了,毕竟万兆网络成本颇高。与机房内的其他小伙伴们用千兆网络互相沟通也算顺畅,给另一台机器的CPU朋友发送1K的书信,最快七八个小时就可以送过去了。但是1K的书信经过层层包裹,实际也写不了多少话。更要命的是,网卡们的沟通手续繁杂,每次网络沟通前的 “你好能听到我吗?——我能听到,你那边能听到我吗?——我也能听到你,那我们开始吧!” 这样的握手确认都要花掉很长的时间,不过不能当面沟通,也只能这样了。这还好,最恐怖的是与其他城市的小伙伴沟通,有时候传递消息要花费好几年呢!
由此可见,对于CPU先生来说,想要让工作充实起来实在不容易,不过多亏了内存组的小伙伴帮忙分批缓存往返于I/O组的数据,矛盾才有所缓解。
这个图只能明显看出涉及I/O的时间条,我们转换成对数刻度的图看一下:
这个图并不是直观的比例,横轴上每个刻度是一个数量级,可见I/O的速度与CPU和内存相比是要差几个数量级的。由此可见,对于大型高并发场景下的Web应用,缓存有多重要,更高的缓存命中率就意味着性能。
- 并行化:使用更多的线程和硬件资源;
- 异步化:基于现有的资源来提高执行效率。
3. 基础概念
在介绍主题之前先普及几个概念:
3.1 Backpressure(背压)
背压是一种常用策略,使得发布者拥有无限制的缓冲区存储元素,用于确保发布者发布元素太快时,不会去压制订阅者。
3.2 Reactive Streams(响应式流)
一般由以下组成:
- 发布者:发布元素到订阅者
- 订阅者:消费元素
- 订阅:在发布者中,订阅被创建时,将与订阅者共享
- 处理器:发布者与订阅者之间处理数据
3.3 Mono 和 Flux
- Mono:实现发布者,并返回 0 或 1 个元素
- Flux:实现发布者,并返回 N 个元素
4. Spring Webflux
Spring Boot Webflux 是基于 Reactor 实现的。Spring Boot 2.0 包括一个新的 spring-webflux 模块。该模块包含对响应式 HTTP 和 WebSocket 客户端的支持,以及对 REST,HTML 和 WebSocket 交互等程序的支持。一般来说,Spring MVC 用于同步处理,Spring Webflux 用于异步处理。
Spring Boot Webflux 有两种编程模型实现,一种类似 Spring MVC 注解方式,另一种是使用其功能性端点方式。
4.1 适用性
一图就很明确了,WebFlux 和 MVC 有交集。但是注意:
- MVC 能满足场景的,就不需要更改为 WebFlux。
- 要注意容器的支持,可以看看下面内嵌容器的支持。
- 微服务体系结构,WebFlux 和 MVC 可以混合使用。尤其开发 IO 密集型服务的时候,选择 WebFlux 去实现。
4.2 内嵌容器
跟 Spring Boot 大框架一样启动应用,但 WebFlux 默认是通过 Netty 启动,并且自动设置了默认端口为 8080。另外还提供了对 Jetty、Undertow 等容器的支持。开发者自行在添加对应的容器 Starter 组件依赖,即可配置并使用对应内嵌容器实例。
但是要注意,必须是 Servlet 3.1+ 容器,如 Tomcat、Jetty;或者非 Servlet 容器,如 Netty 和 Undertow。
4.3 数据库
支持 reactive 编程的数据库只有 MongoDB , redis , Cassandra , Couchbase 。
4.4 快速上手
工程依赖
代码清单:spring-boot-webflux/pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Service 类
代码清单:spring-boot-webflux/src/main/java/com/springboot/springbootwebflux/service/impl/UserServiceImpl.java
@Service
public class UserServiceImpl implements UserSerivice {
private static Map<Long, User> map = new HashMap<>();
static {
map.put(1L, new User(1L, "www.geekdigging.com", 18));
map.put(2L, new User(2L, "极客挖掘机", 28));
}
@Override
public Mono<User> getUserById(Long id) {
return Mono.just(map.get(id));
}
}
Controller 类
代码清单:spring-boot-webflux/src/main/java/com/springboot/springbootwebflux/controller/UserController.java
@RestController
public class UserController {
@Autowired
UserSerivice userSerivice;
@GetMapping("/getUserById/{id}")
public Mono<User> getUserById(@PathVariable Long id) {
return userSerivice.getUserById(id);
}
}
通过上面的示例可以发现,开发模式和之前 Spring MVC 的模式差别不是很大,只是在方法的返回值上有所区别。
5. 示例代码
6. 参考
https://blog.csdn.net/get_set/article/details/79466402
http://www.ityouknow.com/springboot/2019/02/12/spring-boot-webflux.html
https://www.cnblogs.com/limuma/p/9315442.html
Spring Boot (十四): 响应式编程以及 Spring Boot Webflux 快速入门的更多相关文章
- (转)Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门
http://www.ityouknow.com/springboot/2019/02/12/spring-boot-webflux.html Spring 5.0 中发布了重量级组件 Webflux ...
- Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门
Spring 5.0 中发布了重量级组件 Webflux,拉起了响应式编程的规模使用序幕. WebFlux 使用的场景是异步非阻塞的,使用 Webflux 作为系统解决方案,在大多数场景下可以提高系统 ...
- 浅谈Spring 5的响应式编程
这篇使用Spring 5进行响应式编程的入门文章展示了你现在可以使用的一些新的non-blocking, asynchronous.感谢优锐课老师给予的指导! 近年来,由于响应式编程能够以声明性的方式 ...
- 【SpringBoot】SpringBoot2.0响应式编程
========================15.高级篇幅之SpringBoot2.0响应式编程 ================================ 1.SprinBoot2.x响应 ...
- 响应式编程基础教程:Spring Boot 与 Lettuce 整合
本文主要介绍响应式编程访问 Redis,以及 Spring Boot 与 Lettuce 的整合使用. Lettuce 是可扩展性线程安全的 Redis 客户端,用于同步.异步和响应式使用.如果多个线 ...
- Spring 5 响应式编程
要点 Reactor 是一个运行在 Java8 之上的响应式流框架,它提供了一组响应式风格的 API 除了个别 API 上的区别,它的原理跟 RxJava 很相似 它是第四代响应式框架,支持操作融合, ...
- Java9第四篇-Reactive Stream API响应式编程
我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 ...
- Spring WebFlux 响应式编程学习笔记(一)
各位Javaer们,大家都在用SpringMVC吧?当我们不亦乐乎的用着SpringMVC框架的时候,Spring5.x又悄(da)无(zhang)声(qi)息(gu)的推出了Spring WebFl ...
- Spring Boot(十四):spring boot整合shiro-登录认证和权限管理
Spring Boot(十四):spring boot整合shiro-登录认证和权限管理 使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公司都会涉 ...
随机推荐
- 最小生成树问题---Prim算法学习
一个具有n个节点的连通图的生成树是原图的最小连通子集,它包含了n个节点和n-1条边.若砍去任一条边,则生成树变为非连通图:若增加一条边,则在图中形成一条回路.本文所写的是一个带权的无向连通图中寻求各边 ...
- Netty源码分析 (五)----- 数据如何在 pipeline 中流动
在上一篇文章中,我们已经了解了pipeline在netty中所处的角色,像是一条流水线,控制着字节流的读写,本文,我们在这个基础上继续深挖pipeline在事件传播 Unsafe 顾名思义,unsaf ...
- .net core 部署到windows上的方法与 系统中相关问题的解决
前言 Net core 项目部门在Windows有很多种方式,大致有以下几种, dotnet 命令, iis(windowshosts), 一些开源的应用容器(docker ) 基于一些exe 程序, ...
- Java日志之Slf4j,Log4J,logback原理总结
几乎任何应用,一定是需要日志的. 那么,面对种类繁多的日志框架和配置,我们该何去何从? 1.前奏:我是在研究mybatis源码的过程中才意识到需要搞明白日志原理这回事,因为mybatis(和一些其他开 ...
- java读写文件IO
package Common.readFile; import Common.tool.User; import com.fasterxml.jackson.databind.ObjectMapper ...
- sql 多行、一行 互转
原始数据: 期望数据: IF OBJECT_ID('temp_20170701','u') IS NOT NULL DROP TABLE temp_20170701 CREATE TABLE temp ...
- AutoCompleteTextView自动完成文本框
AutoCompleteTextView是从EditText派生出来的,比普通编辑框多了一个功能,当用户输入一定字符后,自动完成文本框会显示一个下拉单,供用户选择,当选中一个后,被选中的内容会显示在文 ...
- Winforn中使用代码动态生成控件
场景 有时候需要根据配置文件在窗体中使用代码动态生成控件. 比如读取xml配置文件中的节点数量,然后在窗体中生成指定数量的RadioGroup控件. 实现 新建一个窗体,在窗体的加载完之后的事件中 p ...
- Git同步更新操作GitHub和码云仓库上面的代码
一.前言 问题: 小编在生活中,一般都是将代码保存到github上,但由于国内的码云仓库确实速度比github快很多,用起来也很方便,于是后来就慢慢转码云了,当然小编在github上的代码也不想放弃更 ...
- librosa语音信号处理
librosa是一个非常强大的python语音信号处理的第三方库,本文参考的是librosa的官方文档,本文主要总结了一些重要,对我来说非常常用的功能.学会librosa后再也不用用python去实现 ...