什么是响应式编程
响应式编程(Reactive Programming)是一种编程范式,它专注于 异步数据流 和 变化传播。
响应式编程的核心思想是“数据流是第一等公民”,程序的逻辑建立在数据流的变化之上。
响应式编程的几个核心概念:
1) 数据流:响应式编程中,数据以流(Streams)的形式存在。流就像一条河,源源不断、有一个流向(比如从A系统到B系统再到C系统),它可以被过滤、观测、或者跟另一条河流合并成一个新的流。
比如用户输入、网络请求、文件读取都可以是数据流,可以很轻松地对流进行处理。
比如Java 8的Stream APl,下列代码中将数组作为依次进行过滤、转换、汇聚。
list.staram()
.filter()
.map()
.collect();
2) 异步处理:响应式编程是异步的,即操作不会阻塞线程,而是通过回调或其他机制在未来某个时间点处理结果。这提高了应用的响应性和性能。
3) 变化传播:当数据源发生变化时,响应式编程模型会自动将变化传播到依赖这些数据源的地方。这种传播是自动的,不需要显式调用。
举个例子,有一只股票涨了,所有 订阅 了这只股的人,都会同时收到 APP 的通知,不用你自己盯着看。
注意,响应式编程更倾向于声明式编程风格,通过定义数据流的转换和组合来实现复杂的逻辑。比如,可以利用 map、fiter 等函数来实现数据转换,而不是将一大堆复杂的逻辑混杂在一个代码块中。
什么是RxJava
更加详细请见官网
RxJava 是一个基于事件驱动的、利用可观测序列来实现异步编程的类库,是响应式编程在 Java 语言上的实现。
这个定义中有几个概念,我们分别解释。
1. 事件驱动
事件可以是任何事情,如用户的点击操作、网络请求的结果、文件的读写等。事件驱动的编程模型是通过事件触发行动。
比如前端开发中,用户点击按钮后会进行弹窗,这就是“点击事件”触发了“弹窗行动”。
// 前端按钮点击
btn.onClick(() -> {
// 弹窗
showModel();
})
在 Rxava 中,事件可以被看作是数据流中的数据项,称为“事件流“或“数据流”。每当一个事件发生,这个事件就会被推送给那些对它感兴趣的观察者(Observers)。
2. 可观测序列
可观测序列是指一系列按照时间顺序发出的数据项,可以被观察和处理。可观测序列提供了一种将数据流和异步事件建模为一系列可以订阅和操作的事件的方式。
可以理解为在数据流的基础上封装了一层,多加了一点方法。
核心知识点
观察者模式
RxJava 是基于 观察者模式 实现的,分别有观察者和被观察者两个角色,被观察者会实时传输数据流,观察者可以观测到这些数据流。
基于传输和观察的过程,用户可以通过一些操作方法对数据进行转换或其他处理。
在 RxJava 中,观察者就是 Observer,被观察者是 Observable 和 Flowable。
Observable 适合处理相对较小的、可控的、不会迅速产生大量数据的场景。它不具备背压处理能力,也就是说,当数据生产速度超过数据消费速度时,可能会导致内存溢出或其他性能问题。
Flowable 是针对背压(反向压力)问题而设计的可观测类型。背压问题出现于数据生产速度超过数据消费速度的场景。Flowable提供了多种背压策略来处理这种情况,确保系统在处理大量数据时仍然能够保持稳定。
被观察者.subscribe(观察者),它们之间就建立的订阅关系,被观察者传输的数据或者发出的事件会被观察者观察到。
常用操作符
详见官网。
事件
Rxava 也是一个基于事件驱动的框架,我们来看看一共有哪些事件,分别在什么时候触发:
1) onNext,被观察者每发送一次数据,就会触发此事件。
2) onError,如果发送数据过程中产生意料之外的错误,那么被观察者可以发送此事件。
3) onComplete,如果没有发生错误,那么被观察者在最后一次调用 onNext 之后发送此事件表示完成数据传输。对应的观察者得到这些事件后,可以进行一定处理,例如:
flowable.observeOn(Schedulers.io())
.doOnNext(item -> {
System.out.println("来数据啦" + item.toString());
})
.doOnError(e -> {
System.out.println("出错啦" + e.message());
})
.doOnComplete(() -> {
System.out.println("数据处理完啦");
}).subscribe();
RxJava Demo演示
(1)引入依赖
<dependencies>
<!--https://open.bigmodel.cn/dev/api#sdk_install-->
<dependency>
<groupId>cn.bigmodel.openapi</groupId>
<artifactId>oapi-java-sdk</artifactId>
<version>release-V4-2.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.1.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.1.12</version>
<scope>test</scope>
</dependency>
</dependencies>
(2)编写单元测试
@SpringBootTest
public class RxJavaTest {
@Test
public void rxJavaDemo() {
// 创建一个流,每秒发射一个递增的数字(数据流变化)
Flowable<Long> flowable = Flowable.interval(1, TimeUnit.SECONDS)
.map(i -> i + 1)
.subscribeOn(Schedulers.io()); // 指定线程池
// 订阅 Flowable 流,并打印每个接收到的数字
flowable.observeOn(Schedulers.io())
.doOnNext(i -> System.out.println("Received: " + i))
.subscribe();
// 让主线程休眠,以便观察输出
ThreadUtil.sleep(10000L);
}
}
以上代码解析:
1. subscribeOn() 代码之前就是具体执行的业务逻辑,并且指定线程池去执行。
2. observeOn() 订阅线程池,对其进行监控。
3. doOnNext() 是触发的事件,被观察者每次一发出数据,就监控到,这里就是每秒钟都监控到。
4. subscribe() 相当于监控结束。
5. 阻塞主线程,以便观察结果。