Spring Boot 2.x实战86 - 响应式编程1 - Project Reactor

Spring 5.x的最大的更新是将响应式编程作为头等的支持,响应式开发将极大的提升应用系统的性能。响应式应用是完全异步和非阻碍的,需要应用的每个环节都是异步非阻碍的,所以Spring对响应式编程进行了全角度的支持:

  • Web:Spring WebFlux和WebFlux.fn
  • 数据库: Reactive Spring Data
  • 安全:Reactive Spring Security
  • 客户端:WebClient

Spring 的响应式编程是以Project Reactor为基石的,它用来构建基于JVM Reactive Streams规范的非阻碍式应用。

1. Project Reactor

使用Intellij IDEA新建Gradle应用:

GroupId: top.wisely

ArtifactId:learning-reactor

依赖添加:

dependencies {
    compile 'io.projectreactor:reactor-core:3.2.9.RELEASE'
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

1.1 Reactive Streams的基础接口

Reactor基于Reactive Streams规范,我们先了解一下Reactive Streams的主要接口:

  • Publisher:顾名思义为为发布者,是一些列数据的提供者;它根据订阅者(Subscriber)的要求将数据推送给订阅;一个发布者可以服务多个订阅者。

    public interface Publisher<T> {
        public void subscribe(Subscriber<? super T> s);
    }
    

    订阅者通过subscribe方法订阅发布者,请求发布者开始传递数据;它可以被调用多次,每一次调用都会开始一个新的订阅(Subscription);每一个订阅只为一个订阅者服务。

  • Subscriber:订阅者,

    public interface Subscriber<T> {
    
        public void onSubscribe(Subscription s); //1
      
        public void onNext(T t); //2
    
        public void onError(Throwable t); //3
    
        public void onComplete(); //4
    }
    
    1. Publisher.subscribe(Subscriber)执行时被调用。此时没有数据传输直至Subscription.request(long)被调用;
    2. 当请求Subscription.request(long),由发布者发送的数据通知;方法会被一次或多次被调用,这依赖于Subscription.request(long)中定义的最大数量。
    3. 失败结束状态;
    4. 成功结束状态。
  • Subscription:订阅代表一次订阅者订阅发布者的生命周期;它只能被一个订阅者使用,它既可以用来通知传递数据也可以取消传递。

    public interface Subscription {
    
        public void request(long n); //1
    
        public void cancel(); //2
    }
    
    1. 若不调用此方法,发布者不会发送任何数据;参数n的最大取值为Long.MAX_VALUE,若取值为Long.MAX_VALUE意味着发布者的数据是无限的;
    2. 请求发布者停止发送数据并清理资源。
  • Processor:处理器代表一个处理阶段,它即是订阅者又是发布者。A Processor represents a processing stage—which is both a Subscriber and a Publisher and obeys the contracts of both

    public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
    }
    

    <T> : 订阅者接受的数据类型;
    <R> : 发布者发布数据的类型。

Reactor提供了Provider接口的两个实现FluxMono

1.2 FluxMono

Flux是发送0到n个数据的发布者,而Mono发送0到1个数据。

1.2.1 构建发布者

我们如何构建FluxMono提供者呢?我们可以通过它们的静态方法来构建。

  • 构建Flux

    Flux<String> flux1 = Flux.just("a", "b", "b");
    Flux<String> flux2 = Flux.fromArray(new String[]{"c", "d", "e"});
    Flux<String> flux3 = Flux.fromStream(Stream.of("e", "f", "g"));
    Flux<Integer> flux4 = Flux.range(2019, 3);
    
  • 构建Mono

    Mono<String> mono1 = Mono.just("a");
    Mono<String> mono2 = Mono.from(Flux.just("b"));
    
1.2.2 订阅发布者

若不主动订阅发布者,将不会有任何数据发送;订阅者可以是Consumer函数接口或者是Subscriber接口的实现。

  • 订阅Flux

    System.out.println("-------------");
    flux1.subscribe(System.out::print);
    System.out.println();
    flux2.subscribe(System.out::print);
    System.out.println();
    flux3.subscribe(System.out::print);
    System.out.println();
    flux4.subscribe(new Subscriber<Integer>() {
        volatile Subscription subscription;
        @Override
        public void onSubscribe(Subscription s) {
            subscription = s;
            System.out.println("初始化请求一个数据");
            subscription.request(1);
        }
    
        @Override
        public void onNext(Integer integer) {
            System.out.println("当前数据:" + integer);
            System.out.println("再请求一个数据");
            subscription.request(1);
        }
    
        @Override
        public void onError(Throwable t) {
            System.out.println(t.getMessage());
        }
    
        @Override
        public void onComplete() {
            System.out.println("处理完成");
        }
    });
    

在这里插入图片描述

  • 订阅Mono

    mono1.subscribe(System.out::println);
    mono2.subscribe(new Subscriber<String>() {
        volatile Subscription subscription;
        @Override
        public void onSubscribe(Subscription s) {
            subscription = s;
            System.out.println("初始化请求一个数据");
            subscription.request(1);
        }
    
        @Override
        public void onNext(String s) {
            System.out.println("当前数据:" + s);
            System.out.println("再请求一个数据");
            subscription.request(1);
        }
    
        @Override
        public void onError(Throwable t) {
            System.out.println(t.getMessage());
        }
    
        @Override
        public void onComplete() {
            System.out.println("处理完成");
        }
    });
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iyRvnoTn-1593573200946)(images/reactive-mono.png)]
    在这里插入图片描述

1.2.3 处理操作

FluxMono也可以像Stream一样对其中的数据进行处理操作。

Flux<Integer> flux1 = Flux.just(1, 6, 4, 3, 5, 2);
flux1
  .map(i -> i * 3) //1
  .filter(i -> i % 2 == 0) //2 
  .sort(Comparator.comparingInt(Integer::intValue)) //3
  .subscribe(System.out::println);
  1. 将发布者中的所有数据都乘以3;
  2. 过滤出数据中的偶数;
  3. 将数据进行排序。

在这里插入图片描述

新书推荐:

我的新书《从企业级开发到云原生微服务:Spring Boot 实战》已出版,内容涵盖了丰富Spring Boot开发的相关知识
购买地址:https://item.jd.com/12760084.html
在这里插入图片描述

主要包含目录有:

第一章 初识Spring Boot(快速领略Spring Boot的美丽)
第二章 开发必备工具(对常用开发工具进行介绍:包含IntelliJ IDEA、Gradle、Lombok、Docker等)
第三章 函数式编程
第四章 Spring 5.x基础(以Spring 5.2.x为基础)
第五章 深入Spring Boot(以Spring Boot 2.2.x为基础)
第六章 Spring Web MVC
第七章 数据访问(包含Spring Data JPA、Spring Data Elasticsearch和数据缓存)
第八章 安全控制(包含Spring Security和OAuth2)
第九章 响应式编程(包含Project Reactor、Spring WebFlux、Reactive NoSQL、R2DBC、Reactive Spring Security)
第十章 事件驱动(包含JMS、RabbitMQ、Kafka、Websocket、RSocket)
第11章 系统集成和批处理(包含Spring Integration和Spring Batch)
第12章 Spring Cloud与微服务
第13章 Kubernetes与微服务(包含Kubernetes、Helm、Jenkins、Istio)
多谢大家支持。

猜你喜欢

转载自blog.csdn.net/wiselyman/article/details/107059332