应用响应式Web开发组件-响应式编程和Spring Boot
共 3941字,需浏览 8分钟
·
2023-08-30 03:34
当下,对于具有广大用户群体的新型互联网应用而言,它们基本都需要 考虑如何高效应对用户流量、如何确保系统弹性等核心技术主题。在理论和 实践的结合下,响应式编程是一种新型的编程模型,是确保系统弹性的一款 强有力的武器。在响应式编程领域,存在一套完整的响应式流规范以及实现 这一规范的开发工具。在现实中,开发人员通常不会直接使用这些偏底层的 开发工具来开发应用程序,而是借助于特定的开发框架。而我们日常开发中 每天都在使用的Spring就是这样一个支持响应式编程的开发框架。
在2017年,Spring发布了新版本Spring 5,这是自Spring 4发布以来将 近4年的时间中所发布的第一个全新版本。Spring 5引入了很多核心功能,重 要的是它全面拥抱了响应式编程的设计思想和实践。
Spring 5的响应式编程模型以Project Reactor库为基础,而后者则实现 了响应式流规范。事实上,Spring Boot从2.x版本开始全面依赖Spring 5。
Spring Boot为我们提供了一系列响应式编程组件,而本章将重点关注如何使 用Spring Boot框架来开发响应式Web服务。
响应式编程和Spring Boot
响应式编程是一种新的编程技术,其目的是构建响应式系统。对于响应 式系统而言,任何时候都需要确保其具备即时响应性,这是大多数日常业务 场景所需要的,但却是一项非常复杂而有挑战性的任务,需要对相关技术有 深入的了解。本节将讨论这些技术。
响应式流规范和实现框架
对于响应式编程而言,首先要明确的概念是数据流(Data Stream)。简 单来讲,所谓的流就是由生产者生产并由一个或多个消费者消费的元素序 列。而一旦有了数据流,那么就势必面临流量控制问题。流量控制是讨论数 据流的核心话题。而针对如何控制流量,业界存在一个响应式流规范,以及 一批实现了该规范的开发工具。
1. 响应式流规范
Java API版本的响应式流只包含四个接口,即Publisher<T>、 Subscriber<T>、Subscription和Processor<T,R>。
发布者(Publisher)是潜在的包含无限数量的有序元素的生产者,它根 据收到的请求向当前订阅者发送元素。Publisher<T>接口定义如代码清单5-1 所示。
代码清单5-1 Publisher<T>接口定义代码
public interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
订阅者(Subscriber)从发布者那里订阅并接收元素。发布者向订阅者 发送订阅令牌(Subscription Token)。通过订阅令牌,订阅者就可以向发 布者请求多个元素。当元素准备就绪时,发布者就会向订阅者发送合适数量 的元素。然后订阅者可以请求更多的元素,发布者也可能有多个来自订阅者 的待处理请求。Subscriber <T>接口定义如代码清单5-2所示。
当执行发布者的subscribe()方法时,发布者会回调订阅者的 onSubscribe()方法。在这个方法中,通常订阅者会借助传入的Subscription 对象向发布者请求n个数据。然后发布者通过不断调用订阅者的onNext()方法 向订阅者发出最多n个数据。如果数据全部发完,则会调用onComplete()方法 告知订阅者流已经发完;如果有错误发生,则通过onError()方法发出错误提 示消息,这时同样也会终止数据流。
订阅(Subscription)表示订阅者订阅的一个令牌。当订阅请求成功 时,发布者将其传递给订阅者。订阅者使用订阅令牌与发布者进行交互,例 如请求更多的元素或取消订阅。Subscription接口定义如代码清单5-3所示。
当发布者调用subscribe()方法注册订阅者时,会通过订阅者的回调方法 onSubscribe()传入Subscription对象,之后订阅者就可以使用这个 Subscription对象的request()方法向发布者请求数据。
处理器(Processor)充当订阅者和发布者之间的转换器 (Transformer)。Processor<T,R>订阅类型T的数据元素,接收并转换为类 型R的数据,发布该数据。Processor接口同时继承了Publisher和Subscriber 接口,其定义如代码清单5-4所示。
上述四个接口是各个响应式开发库之间互相实现兼容的桥梁,响应式流 规范也仅仅聚焦于此,而对诸如转换、合并、分组等的操作一概未做要求, 因此是一个非常抽象且精简的接口规范。
作为总结,我们可以把响应式流规范核心接口的交互方式梳理成图5-1。
可以看到,图5-1中所示的交互方式一共包含如下7个步骤。
1)当发布者使用subscribe()方法实现对该发布者的订阅时,首先会创 建一个具有相应逻辑的Subscription对象,这个Subscription对象定义了如 何处理请求,以及如何发出数据。
2)然后发布者将这个Subscription通过订阅者的onSubscribe()方法传 给订阅者。
3)在订阅者的onSubscribe()方法中,需要通过Subscription的request ()方法发起第一次请求。
4)Subscription收到请求,就可以通过回调订阅者的onNext()方法发出 元素,有多少发多少,但不能超过请求的个数。
5)订阅者在onNext()方法中通常定义对元素的处理逻辑,处理完成之 后,可以继续发起请求。
6)发布者根据需要继续满足订阅者的请求。
7)如果发布者的元素序列正常结束,就通过订阅者的onComplete()方法 予以告知。如果序列发送过程中有错误,则通过订阅者的onError()方法予以 告知并传递错误提示。这两种情况都会导致序列终止,订阅过程结束。
2. Project Reactor
Spring 5引入了响应式编程机制,并默认集成了Project Reactor(下文 简称为Reactor)作为该机制的实现框架。Reactor诞生较晚,可以认为它是 第二代响应式开发框架。所以它是一款完全基于响应式流规范设计和实现的 工具库,在使用上直观易懂。
在Reactor框架中,数据流的表现形式如图5-2所示。
图5-2中的数据流模型从语义上可以用如下公式表示:
onNext x 0..N [onError | onComplete]
上述公式包含了如下三种不同类型的方法调用,分别处理不同场景下的 消息通知。
onNext():正常包含元素的消息通知。
onComplete():序列结束的消息通知。
onError():序列出错的消息通知,可以没有。
按照响应式流规范,当这些消息通知产生时,订阅者中对应的 onNext()、onComplete()和onError()这三个方法将被调用。如果序列没有出 错,则onError()方法不会被调用;而如果不调用onComplete()方法,我们就 会得到一个无限异步序列。通常,无限异步序列应该只用于测试等特殊场 景。
针对数据流,Reactor提供了两个核心组件,即Flux和Mono。其中Flux代 表包含0到n个元素的异步序列,而Mono则表示包含0个或1个元素的异步序 列。
创建Flux的方式非常多,这些方式可以分成两大类,一类是充分利用 Flux的静态方法,另一类则是动态创建Flux。这里的静态方法常见的包括 just()、fromArray()、fromIterable()、fromStream()、empty()、 error()、never()、range()、interval()等,而动态方法则包括generate() 和create()。创建Mono的方式也类似。 另外,和其他主流的响应式编程框架一样,Reactor框架的设计目标也是 为了简化响应式流的使用方法。为此,Reactor框架为我们提供了大量操作符 用于操作Flux和Mono对象。常见的包括用于数据转换的flatMap、用于数据过 滤的filter、用于操作组合的zipWith、用于条件控制的defaultIfEmpty,以 及subscribe和log等工具操作符。
由于本章的重点是介绍Spring WebFlux,而Project Reactor是WebFlux 的底层框架,我们一般不会直接使用该框架开发Web应用程序。因此,针对 Flux和Mono的创建方法以及各种操作符,我们不打算做全面而细致的介绍, 读者可参考Reactor框架的官方文档以及笔者翻译的《Spring响应式编程》一 书做进一步了解。
本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。