反应式系统介绍
官网的描述如下:
反应式系统具有某些特性,使其成为低延迟、高吞吐量工作负载的理想选择。Project Reactor 和 Spring 产品组合协同工作 ,使开发人员能够构建响应式、弹性、弹性和消息驱动的企业级响应式系统。
反应式处理是一种范例,它使开发人员能够构建可以处理背压(流控制)的非阻塞异步应用程序
反应式系统更好地利用现代处理器。此外,在响应式编程中包含背压可确保解耦组件之间更好的弹性
背压
背压是指数据的生产者和消费者之间的一种协调机制,当数据的生产者生产数据的速度大于消费者消费数据的速度时,就会出现背压。react streams的背压协议规定了当订阅者无法处理数据时,发布者应该暂停数据的发布。
当订阅者可以处理数据时,发布者应该继续发布数据。这样就可以保证数据的生产者和消费者之间的速度一致,避免数据的丢失。
reactive Stream 规范
Reactive Stream (响应式流/反应流) 是JDK9引入的一套标准,是一套基于发布/订阅模式的数据处理规范
react streams的核心是Publisher, Subscriber, Subscription, Processor
// 接口定义了连接发布者和订阅者的方法
Subscription
// 接口定义了发布者的方法
Publisher<T>
// 接口定义了订阅者的方法
Subscriber<T>
// 接口定义了处理器
Processor<T,R>
- 发布者Publisher:发布元素到订阅者
- 订阅者Subscriber:消费元素
- 订阅Subscription:在发布者中,订阅被创建时,将与订阅者共享
- 处理器Processor:发布者与订阅者之间处理数据
JDK9中Reactive Stream的实现规范 通常被称为 Flow API ,通过java.util.concurrent.Flow 和java.util.concurrent.SubmissionPublisher 类来实现响应式流
发布者
public interface Publisher<T> {
void subscribe(Subscriber<? super T> s);
}
订阅者
public interface Subscriber<T> {
void onSubscribe(Subscription s);
void onNext(T t);
void onError(Throwable t);
void onComplete();
}
其中的onSubscribe方法,是当订阅者订阅发布者后,发布者会调用订阅者的onSubscribe方法,将订阅者的订阅对象传递给订阅者。
其中的onNext方法,是当发布者发布数据后,会调用订阅者的onNext方法,将数据传递给订阅者。
其中的onError方法,是当发布者发布数据出现异常后,会调用订阅者的onError方法,将异常传递给订阅者。
其中的onComplete方法,是当发布者发布数据完成后,会调用订阅者的onComplete方法,通知订阅者数据发布完成。
订阅
public interface Subscription {
void request(long n);
void cancel();
}
Subscription是一个订阅,它负责订阅发布者的数据,订阅者可以订阅多个发布者。
其中的request方法中的n参数,是订阅者请求发布者发布数据的数量。
其中的cancel方法,是方便订阅者取消订阅发布者的数据。
processor
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}
webFlux
webFlux的底层实现基于Netty作为网络通信,spring cloud gateway基于spring webFlux,webFlux是基于reactive Stream规范实现的project reactor 反应式编程框架的web反应式编程框架
看官网的描述:
Project Reactor是一个完全无阻塞的基础,包括背压支撑。它是Spring生态系统中反应式堆栈的基础,并在Spring WebFlux,Spring Data和Spring Cloud Gateway等项目中都有特色。
开发人员从阻塞代码转向非阻塞代码的主要原因之一是效率。反应式代码用更少的资源完成更多的工作。Project Reactor 和 Spring WebFlux 使开发人员能够利用多核下一代处理器,处理潜在的大量并发连接。通过反应式处理,您可以用更少的微服务实例满足更多的并发用户
webFlux的基准
可以看出spring WebFlux对标的是spring MVC 他们一个基于反应式框架,一个基于servlet
webFlux重要类
Flux和Mono这两个 Project Reactor 的核心类:
- Mono:实现发布者 Publisher,并返回 0 或 1 个元素。
- Flux:实现发布者 Publisher,并返回 N 个元素
Flux
//可以指定序列中包含的全部元素。创建出来的 Flux 序列在发布这些元素之后会自动结束。
just
// 可以从一个数组、Iterable 对象或 Stream 对象中创建 Flux 对象。
fromArray(),fromIterable()和 fromStream()
// 创建一个不包含任何元素,只发布结束消息的序列,在响应式编程中,流的传递是基于元素的,empty表示没有任何元素,所以不会进行后续传递,需要用switchIfEmpty等处理
empty()
// 创建一个只包含错误消息的序列
error(Throwable error)
// 创建一个不包含任何消息通知的序列
never()
//创建包含从 start 起始的 count 个数量的 Integer 对象的序列
range(int start, int count)
Mono
// 创建对象
just
// 创建一个不包含任何元素,只发布结束消息的序列
empty
// 抛出异常
error()
Mono.defer(()->{
return Mono.error(new RuntimeException());
}).subscribe();
webFlux的使用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
@RestController
public class HelloController {
@GetMapping("/hello")
public Mono<String> hello() {
long start = System.currentTimeMillis();
Mono<String> hello = Mono.fromSupplier(() -> getHelloStr());
System.out.println("接口耗时:" + (System.currentTimeMillis() - start));
return hello;
}
private String getHelloStr() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello";
}
}
在 WebFlux 接口中,请求不会被阻塞,所以服务端的接口耗时为 0。
public class TestReactor {
public static void main(String[] args) {
//just():创建Flux序列,并声明数据流,
Flux<Integer> integerFlux = Flux.just(1, 2, 3, 4);//整形
//subscribe():订阅Flux序列,只有进行订阅后才回触发数据流,不订阅就什么都不会发生
integerFlux.subscribe(System.out::println);
Flux<String> stringFlux = Flux.just("hello", "world");//字符串
stringFlux.subscribe(System.out::println);
//fromArray(),fromIterable()和fromStream():可以从一个数组、Iterable 对象或Stream 对象中创建Flux序列
Integer[] array = {1,2,3,4};
Flux.fromArray(array).subscribe(System.out::println);
List<Integer> integers = Arrays.asList(array);
Flux.fromIterable(integers).subscribe(System.out::println);
Stream<Integer> stream = integers.stream();
Flux.fromStream(stream).subscribe(System.out::println);
}
}
更多webFlux请移步传送门