Reactor学习记录
- 基本概念
概述
Reactor 是 Java 反应式编程的框架,Webflux 底层使用的也是该框架,其通过流的方式实现了异步相应。反应式编程通过异步的方式提高了系统的吞吐量,有效利用了系统资源,但其并不能提高响应的速度。其在根本上是一种 pub/sub 模式,通过在发布者与消费者之间的预留通道实现异步响应,类似于 Future 的概念。
reactor是基于reactive stream规范实现的一个响应式编程框架。Reactive stream是一种非阻塞、事件驱动数据流的开发方案,使用函数式编程的概念来操作数据流,系统中某部分的数据变动后会自动更新其他部分。
发布者和订阅者是 Reactor 中有两个最基本的概念,可以简单理解为消息队列中的生产者和消费者的概念。在Reactor中发布者有两个,一个是 Flux,一个是 Mono。Flux 代表的是 0-N 个元素的响应式序列,而 Mono 代表的是 0-1个的元素的结果。
因为流式处理一般将处理多个元素,因此本文主要学习 Flux 相关的内容来理解 Reactor 框架的原理和使用。
基本组成
JDK9 中推出了 Flow API,用以支持 Reactive Programming,即响应式编程。
在响应式编程中,会有一个数据发布者 Publisher 和数据订阅者 Subscriber:
Publisher 发布数据;
Subscriber 接收 Publisher 发布的数据并进行消费;
在 Subscriber 和 Publisher 之间还存在一个 Processor,类似于一个过滤器,可以对数据进行中间处理;
Publisher 与 Subscriber 之间的订阅关系由 Subscription 控制;
publisher:数据发布者
@FunctionalInterface
public static interface Publisher<T> {
public void subscribe(Subscriber<? super T> subscriber);
}
Subscriber 数据消费者
public static interface Subscriber<T> {
public void onSubscribe(Subscription subscription);
public void onNext(T item);
public void onError(Throwable throwable);
public void onComplete();
}
onSubscribe():当与消费者绑定成功时调用该方法;
onNext():当接收到一条发布数据时调用该方法;
onError():当发布者或消费者发生异常时调用该方法;
onComplete():当发布者关闭且所有数据已经被全部消费后调用该方法;
Subscription 订阅关系
public static interface Subscription {
public void request(long n);
public void cancel();
}
request():该方法用于向通道中请求 n 个数据进行处理;
cancel():该方法用于取消发布者和消费者的绑定关系;
Processor 中间处理器
Processor 是数据发布者与消费者中间的处理器,可以对发布者发布的数据进行预处理后再发送给消费者进行消费。
实际上其既是发布者,又是消费者,即在两者中间进行了一次数据的处理转发,其源码如下:
public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
}
发布订阅实例代码:
public class FlowDemo {
public static void main(String[] args) {
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
Flow.Subscriber<String> subscriber = new Flow.Subscriber<String>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
// 向数据发布者请求数据
this.subscription.request(1);
}
@Override
public void onNext(String item) {
System.out.println("接收到消息>>>" + item);
// 接收数据后可以继续接收或取消订阅
this.subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
// 产生异常后直接取消订阅
this.subscription.cancel();
}
@Override
public void onComplete() {
// 发布者所有数据全部被接收,且发布者已经关闭
System.out.println("数据接收完毕~");
}
};
// 将订阅者注册到发布者
publisher.subscribe(subscriber);
// 发布消息
for (int i = 0; i < 10; i++) {
// 发送数据
publisher.submit(String.valueOf(i));
}
// 关闭发布者
publisher.close();
// 维持程序保持开启
while (true) {}
}
Processor 处理器代码
public class ProcessorDemo {
public static void main(String[] args) {
class DataFilter extends SubmissionPublisher<String> implements Flow.Processor<String,String>{
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
this.subscription.request(1);
}
@Override
public void onNext(String item) {
this.submit("【处理后数据】" + item);
this.subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
this.subscription.cancel();
}
@Override
public void onComplete() {
this.close();
}
}
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
DataFilter dataFilter = new DataFilter();
publisher.subscribe(dataFilter);
Flow.Subscriber<String> subscriber = new Flow.Subscriber<String>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
//向数据发布者请求一个数据
this.subscription.request(1);
}
@Override
public void onNext(String item) {
System.out.println("接收到消息>>>" + item);
//接收完成后,可以继续接收或者不接收
//this.subscription.cancel();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
//出现异常,就会来到这个方法,此时直接取消订阅即可
this.subscription.cancel();
}
@Override
public void onComplete() {
//发布者的所有数据都被接收,并且发布者已经关闭
System.out.println("数据接收完毕~");
}
};
dataFilter.subscribe(subscriber);
for (int i = 0; i < 1000; i++) {
// 发送数据
System.out.println("产生数据" + i);
publisher.submit(String.valueOf(i));
}
//关闭发布者
publisher.close();
// 维持程序保持开启
while (true) {}
}
}
Backpressure 回压
Backpressure 回压是指消费能力低于生产能力时,Subscriber 会将 Publisher 发布的数据缓存在 Subscription 中,其长度默认为256,源码如下:
static final int DEFAULT_BUFFER_SIZE = 256;
public static int defaultBufferSize() {
return DEFAULT_BUFFER_SIZE;
}
Backpressure 示例代码
public class FlowDemo0 {
public static void main(String[] args) {
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
Flow.Subscriber<String> subscriber = new Flow.Subscriber<String>() {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
// 向数据发布者请求数据
this.subscription.request(1);
}
@Override
public void onNext(String item) {
System.out.println("接收到消息>>>" + item);
// 等待1秒再接收下一条数据
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 接收数据后可以继续接收或取消订阅
this.subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
// 产生异常后直接取消订阅
this.subscription.cancel();
}
@Override
public void onComplete() {
// 发布者所有数据全部被接收,且发布者已经关闭
System.out.println("数据接收完毕~");
}
};
// 将订阅者注册到发布者
publisher.subscribe(subscriber);
// 发布消息
for (int i = 0; i < 500; i++) {
// 发送数据
System.out.println("产生数据" + i);
publisher.submit(String.valueOf(i));
}
// 关闭发布者
publisher.close();
// 维持程序保持开启
while (true) {}
}
}
Mono 和 flux的api
创建Mono/flux
just():使用已知内容创建;
fromIterable():通过可迭代对象创建;
fromStream():从集合流中创建;
range():通过范围迭代创建;
// 1. 创建 Flux/Mono
// 1.1 使用已知内容创建 Flux
Flux.just(1, 2, 3, 4, "hello", "world")
.subscribe(System.out::println);
// 1.2 通过可迭代对象创建 Flux
Flux.fromIterable(Arrays.asList(1, 2, 3, 4, 5))
.subscribe(System.out::println);
// 1.3 从集合流中创建 Flux
Flux.fromStream(Stream.of(1,2,3,4))
.subscribe(System.out::println);
// 1.4 通过范围迭代创建 Flux
Flux.range(0,10)
.subscribe(System.out::println);
interval():按照从 0 递增的方式自动创建;
delayElements():数据流延时发送方法;
// 2. 创建时常用的方法
// 2.1 interval() 方法可以用来生成从 0 开始递增的 Long 对象的数据序列
Flux.interval(Duration.ofMillis(100))
// 限制执行10次
.take(10)
.subscribe(System.out::println);
// 2.2 delayElements() 方法延时发送
Flux.fromIterable(Arrays.asList(1, 2, 3, 4, 5))
.delayElements(Duration.ofMillis(1000L))
.subscribe(System.out::println);
Exception 异常处理
doOnError():异常监听,监听到异常的处理逻辑;
onErrorReturn():产生异常时返回消息给订阅者;
Flux.just("1", "2", "3")
// concatWith() 可以连接一个新的流
.concatWith(Flux.error(new Exception("手动模拟异常...")))
.doOnError(Throwable::printStackTrace)
.onErrorReturn("产生异常,返回 500...")
.subscribe(System.out::println);
subscribe():可以通过传入参数指定异常处理
参数1:定义正常消费逻辑;
参数2:定义异常处理逻辑;
参数3:定义消费完成的逻辑;
Flux.just("1", "2", "3")
// concatWith() 可以连接一个新的流
.concatWith(Flux.error(new Exception("手动模拟异常...")))
.subscribe(System.out::println,
System.err::println,
() -> System.out.println("完成..."));
onErrorResume():产生异常后重新产生新的流
Flux.just("1", "2", "3")
// concatWith() 可以连接一个新的流
.concatWith(Flux.error(new Exception("手动模拟异常...")))
.onErrorResume(throwable -> {
System.out.println(throwable.getMessage());;
return Flux.just("1", "1", "1");
})
.subscribe(System.out::println);
retry():产生异常后进行重试,参数为重试次数
Flux.just("1", "2", "3")
// concatWith() 可以连接一个新的流
.concatWith(Flux.error(new Exception("手动模拟异常...")))
.retry(1)
.subscribe(System.out::println);
常用的数据处理api
merge():按照所有流的实际产生顺序进行合并;
mergeSequential():按照流合并的次序进行合并,先消费第一个,在消费第二个;
参考:https://blog.csdn.net/zqf787351070/article/details/128724411