再临SpringBoot——Reactive Stream

初识Reactive Stream

Reactive Stream(响应流)是java9引入的一套标准,是基于发布/订阅模式的数据处理规范

响应流作为提供 非阻塞背压 的异步流处理标准的倡议,它旨在解决处理元素流的问题——如何将元素流从发布者传递到订阅着,而不需要发布者阻塞,或者不需要订阅着有限制的缓冲区或丢弃。

理解Reactive Stream,一个概念很关键,背压。什么叫背压?
首先异步消费者会向生产者订阅接受消息,然后当有新的消息可用时,消费者会通过之前订阅时提供的回调函数被再次激活调用。如果生产者发出的信息比消费者能够处理消息的最大亮还多,消费者可能一直被迫地在抓消息,耗费越来越多的资源,埋下了潜在的崩溃隐患。为了防止这一点,需要有一种机制使消费者可以通知生产者来降低消息生成的速度。

打个比方,就像水龙头一样,消费者这边可以控制水流的增加减少和关闭。

Reactive Stream主要接口

Java9通过java.util.concurrent.Flow和java.util.concurrent.SubmissionPublisher类来实现响应式流。

Reactive Stream的主要接口声明都在Flow类里:

  • Publisher:数据项发布者、生产者。
  • Subscriber:数据项订阅者、消费者。
  • Subscription:发布者与订阅着之间的关系纽带,订阅令牌。
  • Processor:数据处理器(发布者和订阅者的中转站,非必要)。

下图显示了发布者和订阅者之间的典型交互顺序。 订阅令牌未显示在图表中。 该图没有显示错误和取消事件。
在这里插入图片描述

处理者(processor)充当订阅者和发布者的处理阶段。 Processor接口继承了Publisher和Subscriber接口。 它用于转换发布者——订阅者管道中的元素。 Processor<T,R>订阅类型T的数据元素,接收并转换为类型R的数据,并发布变换后的数据。 下图显示了处理者在发布者——订阅和管道中作为转换器的作用。 可以拥有多个处理者。
在这里插入图片描述

/**
 * 带 process 的 flow demo
 */

/**
 * Processor, 需要继承SubmissionPublisher并实现Processor接口
 * 
 * 输入源数据 integer, 过滤掉小于0的, 然后转换成字符串发布出去
 */
class MyProcessor extends SubmissionPublisher<String>
		implements Processor<Integer, String> {

	private Subscription subscription;

	@Override
	public void onSubscribe(Subscription subscription) {
		// 保存订阅关系, 需要用它来给发布者响应
		this.subscription = subscription;

		// 请求一个数据
		this.subscription.request(1);
	}

	@Override
	public void onNext(Integer item) {
		// 接受到一个数据, 处理
		System.out.println("处理器接受到数据: " + item);

		// 过滤掉小于0的, 然后发布出去
		if (item > 0) {
			this.submit("转换后的数据:" + item);
		}

		// 处理完调用request再请求一个数据
		this.subscription.request(1);

		// 或者 已经达到了目标, 调用cancel告诉发布者不再接受数据了
		// this.subscription.cancel();
	}

	@Override
	public void onError(Throwable throwable) {
		// 出现了异常(例如处理数据的时候产生了异常)
		throwable.printStackTrace();

		// 我们可以告诉发布者, 后面不接受数据了
		this.subscription.cancel();
	}

	@Override
	public void onComplete() {
		// 全部数据处理完了(发布者关闭了)
		System.out.println("处理器处理完了!");
		// 关闭发布者
		this.close();
	}

}

public class FlowDemo2 {

	public static void main(String[] args) throws Exception {
		// 1. 定义发布者, 发布的数据类型是 Integer
		// 直接使用jdk自带的SubmissionPublisher
		SubmissionPublisher<Integer> publiser = new SubmissionPublisher<Integer>();

		// 2. 定义处理器, 对数据进行过滤, 并转换为String类型
		MyProcessor processor = new MyProcessor();

		// 3. 发布者 和 处理器 建立订阅关系
		publiser.subscribe(processor);

		// 4. 定义最终订阅者, 消费 String 类型数据
		Subscriber<String> subscriber = new Subscriber<String>() {

			private Subscription subscription;

			@Override
			public void onSubscribe(Subscription subscription) {
				// 保存订阅关系, 需要用它来给发布者响应
				this.subscription = subscription;

				// 请求一个数据
				this.subscription.request(1);
			}

			@Override
			public void onNext(String item) {
				// 接受到一个数据, 处理
				System.out.println("接受到数据: " + item);

				// 处理完调用request再请求一个数据
				this.subscription.request(1);

				// 或者 已经达到了目标, 调用cancel告诉发布者不再接受数据了
				// this.subscription.cancel();
			}

			@Override
			public void onError(Throwable throwable) {
				// 出现了异常(例如处理数据的时候产生了异常)
				throwable.printStackTrace();

				// 我们可以告诉发布者, 后面不接受数据了
				this.subscription.cancel();
			}

			@Override
			public void onComplete() {
				// 全部数据处理完了(发布者关闭了)
				System.out.println("处理完了!");
			}

		};

		// 5. 处理器 和 最终订阅者 建立订阅关系
		processor.subscribe(subscriber);

		// 6. 生产数据, 并发布
		// 这里忽略数据生产过程
		publiser.submit(-111);
		publiser.submit(111);

		// 7. 结束后 关闭发布者
		// 正式环境 应该放 finally 或者使用 try-resouce 确保关闭
		publiser.close();

		// 主线程延迟停止, 否则数据没有消费就退出
		Thread.currentThread().join(1000);
	}

}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值