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应用,缓存有多重要,更高的缓存命中率就意味着性能。

  1. 并行化:使用更多的线程和硬件资源;
  2. 异步化:基于现有的资源来提高执行效率。

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. 示例代码

示例代码-Github

示例代码-Gitee

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 快速入门的更多相关文章

  1. (转)Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门

    http://www.ityouknow.com/springboot/2019/02/12/spring-boot-webflux.html Spring 5.0 中发布了重量级组件 Webflux ...

  2. Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门

    Spring 5.0 中发布了重量级组件 Webflux,拉起了响应式编程的规模使用序幕. WebFlux 使用的场景是异步非阻塞的,使用 Webflux 作为系统解决方案,在大多数场景下可以提高系统 ...

  3. 浅谈Spring 5的响应式编程

    这篇使用Spring 5进行响应式编程的入门文章展示了你现在可以使用的一些新的non-blocking, asynchronous.感谢优锐课老师给予的指导! 近年来,由于响应式编程能够以声明性的方式 ...

  4. 【SpringBoot】SpringBoot2.0响应式编程

    ========================15.高级篇幅之SpringBoot2.0响应式编程 ================================ 1.SprinBoot2.x响应 ...

  5. 响应式编程基础教程:Spring Boot 与 Lettuce 整合

    本文主要介绍响应式编程访问 Redis,以及 Spring Boot 与 Lettuce 的整合使用. Lettuce 是可扩展性线程安全的 Redis 客户端,用于同步.异步和响应式使用.如果多个线 ...

  6. Spring 5 响应式编程

    要点 Reactor 是一个运行在 Java8 之上的响应式流框架,它提供了一组响应式风格的 API 除了个别 API 上的区别,它的原理跟 RxJava 很相似 它是第四代响应式框架,支持操作融合, ...

  7. Java9第四篇-Reactive Stream API响应式编程

    我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 ...

  8. Spring WebFlux 响应式编程学习笔记(一)

    各位Javaer们,大家都在用SpringMVC吧?当我们不亦乐乎的用着SpringMVC框架的时候,Spring5.x又悄(da)无(zhang)声(qi)息(gu)的推出了Spring WebFl ...

  9. Spring Boot(十四):spring boot整合shiro-登录认证和权限管理

    Spring Boot(十四):spring boot整合shiro-登录认证和权限管理 使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公司都会涉 ...

随机推荐

  1. EF Core 通过延迟加载获取导航属性数据

    EF 6及以前的版本是默认支持延迟加载(Lazy Loading)的,早期的EF Core中并不支持,必须使用Include方法来支持导航属性的数据加载. 当然在EF Core 2.1及之后版本中已经 ...

  2. Mybatis系列(一)入门

    Mybatis系列(一)入门 mybatis简介 MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结 ...

  3. DNS解析域名的过程

    一.DNS解析域名的过程 1.大的过程可分为三步: (1).在缓存中查找是否之前解析过 (2).在windows系统的host文件中查找 (3).请求DNS服务器 2.小的过程可分为十步: (1).浏 ...

  4. HDFS之Qurom Journal Manager(QJM)实现机制分析

    前言 1.1背景 自从hadoop2版本开始,社区引入了NameNode高可用方案.NameNode主从节点间需要同步操作日志来达到主从节点元数据一致.最初业界均通过NFS来实现日志同步,大家之所以选 ...

  5. 深入浅出Mysql索引的那些事儿

    文章来源:公众号:猿人谷 一.索引的作用 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,所以查询语句的优 ...

  6. MySQL优化之索引原理(二)

    一,前言 ​ 上一篇内容说到了MySQL存储引擎的相关内容,及数据类型的选择优化.下面再来说说索引的内容,包括对B-Tree和B+Tree两者的区别. 1.1,什么是索引 ​ 索引是存储引擎用于快速找 ...

  7. Hive导入数据到HBase,再与Phoenix映射同步

    1. 创建HBase 表 create 'hbase_test','user' 2. 插入数据 put 'hbase_test','111','user:name','jack' put 'hbase ...

  8. 50 (OC)* URL Scheme 网页地址协议

    在Xcode 9 下,新建的工程,在plist文件中注册URL Schemes,从safari无法打开问题 1:URL Scheme是什么 2:URL Scheme有什么作用 3:URL Scheme ...

  9. Python集训营45天—Day07 (面向对象编程进阶)

    目录 1. @property装饰器 2. 魔法方法 3. 类属性和实例属性 4.静态方法和类方法 5. 单继承和多继承 6. 多态 7. del 方法 序言:上个章节我们了解了面向对象的基础知识,这 ...

  10. jenkins构建maven项目:找不到本地依赖包的解决办法

    前言: 我们在构建maven项目时,常常会用到一些特殊的jar包(不能在中央仓库中直接下载到本地仓库如微软不允许以maven的方式直接下载com.microsoft.sqlserver:sqljdbc ...