JDK9新しい流れ応答特性反応ストリーム

JDK9新しい流れ応答特性反応ストリーム

 この章のデータはJDK9応答フロー特性反応ストリームを説明し、導入された反応ストリームは、背圧、だけでなく、インターフェイスとプロセッサを使用する方法を含んで提供JDK9の反応ストリーム上の2つのユースケースは何かということです。

 1.Reactiveストリームコンセプト

 反応性ストリーム(応答ストリーム/反応流)標準JDK9のセットが導入され、治療計画は、データに基づいていますが、パブリッシュ/サブスクライブ・モデルを。非ブロック非同期ストリーム処理背圧規格への取り組みとして提供2013からの応答フロー、。出版社閉塞、または加入者、無制限のバッファまたは破棄を必要とせずに、加入者への発行者から転送されたかエレメンタリ・ストリーム - 流れ要素の処理の問題を解決するために設計されています。より具体的には、反応性ストリームオブジェクトは、「必要な操作を記述するために使用されるインターフェース、プロトコルおよび方法の最小セットを見つけ、エンティティがこの目標を達成する:データの非ブロッキング様式背圧非同期ストリーム」であり

式(反応ストリーム)に生まれた仕様の反応流は、以下の4つのインタフェースを定義しています。

    Subscription 接口定义了连接发布者和订阅者的方法
    Publisher<T> 接口定义了发布者的方法
    Subscriber<T> 接口定义了订阅者的方法
    Processor<T,R> 接口定义了处理器

出生後の反応ストリーム仕様、反応ストリームを達成するために最初からRxJava RxJava 2仕様、スプリング炉(WebFlux基準)によって提供されるフレームワークは、また、反応性ストリーム仕様を達成しているが

 次の図は、加入者と出版社の間の相互作用を示しています

Xnip20200225_131010.png

 2.背圧(背圧)の概念

 情報は、消費者がさらにメッセージの最大量を扱うことができるよりも生産者によって送信された場合、消費者は、メッセージがより多くのリソースを消費してきた把握を余儀なくされる可能性があり、潜在的なクラッシュのリスクを植えました。消費者が生産者に通知し、メッセージの生成速度を下げることができるようにこれを防ぐために、我々はメカニズムが必要です。生産者は、この要件を達成するために、様々な戦略を使用することができ、このメカニズムは、背圧と呼ばれています。

それは単にです

  • 背圧は、パブリッシャとサブスクライバの間の相互作用を指し、
  • 加入者は、過度の浪費につながるか、データ加入者に圧倒パブリッシャがデータを公開することはありませんが、データトラフィックを調整することができ、彼らが必要とどのくらいのデータ発行者に伝えることができます

 達成するための反応性ストリーム仕様の3.JDK9

 実装仕様では、反応ストリームJDK9は、一般的にjava.util.concurrent.Flowクラスjava.util.concurrent.SubmissionPublisherを通じて応答してストリームを達成するために、フローAPIを呼び

 フロークラス中の反応性ストリームのメインインターフェイス宣言でJDK9において、フロークラスは、発行者がデータを使用するための1つまたは複数の加入者を生成するために、ここで、組立フロー制御を確立するための4つの入れ子になった静的なインタフェースを定義しますアイテム:

  • 出版社:項目出版社、プロデューサー
  • 加入者:加入者データ項目、消費者
  • サブスクリプション:パブリッシャとサブスクライバとの間の関係リンク、サブスクリプション・トークン
  • プロセッサ:データ処理装置

Xnip20200225_132212.png

  出版社出版社3.1

  パブリッシャは、サブスクライバーの登録にデータ・ストリームをパブリッシュします。多くの場合、プロジェクト執行非同期加入者を公開するために使用されます。パブリッシャは、各加入者の方法は、コールの厳密な順序に加入していることを確認する必要があります。

  • 購読:パブリッシャーを購読する購読します
        @FunctionalInterface 
        public static interface Flow.Publisher<T> { 
          public void subscribe(Subscriber<? super T> subscriber); 
        }

  3.2加入契約者

  加入者データは、出版社のサブスクリプションを流れ、コールバックを受け取ります。加入者が要求していない場合は、データを受信しません。与えられたサブスクリプション契約(契約)の場合、この方法は、加入者が厳密にシーケンシャルで呼び出します。

  • onSubscribe:出版社呼び出し、このメソッドは非同期転送に加入する加入者は、このメソッドは、メソッド呼び出しのpublisher.subscribe後に実行されます
  • onNext:パブリッシャーは、加入者にデータを渡すために、このメソッドを呼び出します
  • onError:パブリッシャーまたはサブスクライバーが回復不可能なエラーに遭遇したとき、このメソッドが呼び出され、その後、他のメソッドを呼び出すことはありません。
  • onCompleteの:なし呼び出し、他の方法の後に、データが送信されていて、サブスクリプションが終了したときに発生するエラーは、このメソッドが呼び出されていない場合

  3.3サブスクリプションサブスクリプション契約

  Subscription 用于连接 Publisher 和 Subscriber。Subscriber 只有在请求时才会收到项目,并可以通过 Subscription 取消订阅。Subscription 主要有两个方法:

  • request:订阅者调用此方法请求数据
  • cancel:订阅者调用这个方法来取消订阅,解除订阅者与发布者之间的关系
        public static interface Flow.Subscription {
          public void request(long n);
          public void cancel();
        }

  3.4 处理器 Processor

  Processor 位于 Publisher 和 Subscriber 之间,用于做数据转换。可以有多个 Processor 同时使用,组成一个处理链,链中最后一个处理器的处理结果发送给 Subscriber。JDK 没有提供任何具体的处理器。处理器同时是订阅者和发布者,接口的定义也是继承了两者 即作为订阅者也作为发布者 ,作为订阅者接收数据,然后进行处理,处理完后作为发布者,再发布出去。

    /**
     * A component that acts as both a Subscriber and Publisher.
     *
     * @param <T> the subscribed item type
     * @param <R> the published item type
     */
    public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
    }
![Xnip20200225_133449.png](http://cdn.askajohnny.com/Xnip2020-02-25_13-34-49.png)

 4.JDK9 中Reactive Stream(Flow API )规范调用流程

 Publisher是能够发出元素的发布者,Subscriber是接收元素并做出响应的订阅者。当执行Publisher里的subscribe方法时,发布者会回调订阅者的onSubscribe方法,这个方法中,通常订阅者会借助传入的Subscription向发布者请求n个数据。然后发布者通过不断调用订阅者的onNext方法向订阅者发出最多n个数据。如果数据全部发完,则会调用onComplete告知订阅者流已经发完;如果有错误发生,则通过onError发出错误数据,同样也会终止流。

 其中,Subscription相当于是连接Publisher和Subscriber的“纽带(合同)”。因为当发布者调用subscribe方法注册订阅者时,会通过订阅者的回调方法onSubscribe传入Subscription对象,之后订阅者就可以使用这个Subscription对象的request方法向发布者“要”数据了。背压机制正是基于此来实现的

Xnip20200225_133733.png

 5.案例一 响应式基础使用案例

  5.1 以下代码简单演示了SubmissionPublisher 和这套发布-订阅框架的基本使用方式:

  注意要使用JDK9以上的版本

    /**
     * @author johnny
     * @create 2020-02-24 下午5:44
     **/
    @Slf4j
    public class ReactiveStreamTest {
    public static void main(String[] args) throws InterruptedException {
        //1.创建 生产者Publisher JDK9自带的 实现了Publisher接口
        SubmissionPublisher<Integer> publisher = new SubmissionPublisher<>();
        //2.创建 订阅者 Subscriber,需要自己去实现内部方法
        Flow.Subscriber<Integer> subscriber = new Flow.Subscriber<>() {
            private Flow.Subscription subscription;
            @Override
            public void onSubscribe(Flow.Subscription subscription) {
                this.subscription = subscription;
                System.out.println("订阅成功。。");
                subscription.request(1);
                System.out.println("订阅方法里请求一个数据");
            }
            @Override
            public void onNext(Integer item) {
                log.info("【onNext 接受到数据 item : {}】 ", item);
                subscription.request(1);
            }
            @Override
            public void onError(Throwable throwable) {
                log.info("【onError 出现异常】");
                subscription.cancel();
            }
            @Override
            public void onComplete() {
                log.info("【onComplete 所有数据接收完成】");
            }
        };
        //3。发布者和订阅者 建立订阅关系 就是回调订阅者的onSubscribe方法传入订阅合同
        publisher.subscribe(subscriber);
        //4.发布者 生成数据
        for (int i = 1; i <= 5; i++) {
            log.info("【生产数据 {} 】", i );
            //submit是一个阻塞方法,此时会调用订阅者的onNext方法
            publisher.submit(i);
        }
        //5.发布者 数据都已发布完成后,关闭发送,此时会回调订阅者的onComplete方法
        publisher.close();
        //主线程睡一会
        Thread.currentThread().join(100000);
      }
    }

打印输出结果

Xnip20200225_134439.png

 **看结果好像我们看不出来Reactive Stream有什么用 ,其实关键点在 publisher.submit(i); submit它是一个阻塞方法让我们把代码修改一点**

1.将onNext添加耗时操作,模拟业务耗时逻辑2.增加发布者发布数据的数量,模拟真实场景 无限数据

        @Override
            public void onNext(Integer item) {
                log.info("【onNext 接受到数据 item : {}】 ", item);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                subscription.request(1);
            }
        //发布者 生成数据
        for (int i = 1; i <= 1000; i++) {
            log.info("【生产数据 {} 】", i );
            //submit是一个阻塞方法,此时会调用订阅者的onNext方法
            publisher.submit(i);
        }

直接看打印

 **会发现发布者 生成数据到256后就会停止生产,这是因为publisher.submit(i)方法是阻塞的,内部有个缓冲数组最大容量就是256,只有当订阅者发送 subscription.request(1); 请求后,才会从缓冲数组里拿按照顺序拿出数据传给 onNext方法 供订阅者处理,当subscription.request(1)这个方法被调用后,发布者发现数组里没有满才会再生产数据,这样就防止了生产者一次生成过多的数据把订阅者压垮,从而实现了背压机制**

Xnip20200225_135111.png

 6.案例二 响应式带 Processor 使用案例

  6.1创建自定义Processor

    package com.johnny.webflux.webfluxlearn.reactivestream;
    import lombok.extern.slf4j.Slf4j;
    import java.util.concurrent.Flow;
    import java.util.concurrent.SubmissionPublisher;
    /**
     * 自定义 Processor
     *
     * @author johnny
     * @create 2020-02-25 下午1:56
     **/
    @Slf4j
    public class MyProcessor extends SubmissionPublisher<Integer> implements Flow.Processor<Integer, Integer> {
    private Flow.Subscription subscription;
    @Override
    public void onSubscribe(Flow.Subscription subscription) {
        log.info("【Processor 收到订阅请求】");
        //保存订阅关系,需要用它来给发布者 相应
        this.subscription = subscription;
        this.subscription.request(1);
    }
    @Override
    public void onNext(Integer item) {
        log.info("【onNext 收到发布者数据  : {} 】", item);
        //做业务处理。。
        if (item % 2 == 0) {
            //筛选偶数 发送给 订阅者
            this.submit(item);
        }
        this.subscription.request(1);
    }
    @Override
    public void onError(Throwable throwable) {
        // 我们可以告诉发布者, 后面不接受数据了
        this.subscription.cancel();
     }
    @Override
    public void onComplete() {
        log.info("【处理器处理完毕】");
        this.close();
     }
    }

  6.2 运行demo 关联publisher 和 Processor 和 subscriber

    package com.johnny.webflux.webfluxlearn.reactivestream;
    import lombok.extern.slf4j.Slf4j;
    import java.util.concurrent.Flow;
    import java.util.concurrent.SubmissionPublisher;
    import java.util.concurrent.TimeUnit;
    /**
     * 带Processor的案例
     *
     * @author johnny
     * @create 2020-02-25 下午2:17
     **/
    @Slf4j
    public class ProcessorDemo {
    public static void main(String[] args) throws InterruptedException {
        //创建发布者
        SubmissionPublisher<Integer> publisher = new SubmissionPublisher<>();
        //创建 Processor 即是发布者也是订阅者
        MyProcessor myProcessor = new MyProcessor();
        //创建最终订阅者
        Flow.Subscriber<Integer> subscriber = new Flow.Subscriber<>() {
            private Flow.Subscription subscription;
            @Override
            public void onSubscribe(Flow.Subscription subscription) {
                this.subscription = subscription;
                this.subscription.request(1);
            }
            @Override
            public void onNext(Integer item) {
                log.info("【onNext 从Processor 接受到过滤后的 数据 item : {}】 ", item);
                this.subscription.request(1);
            }
            @Override
            public void onError(Throwable throwable) {
                log.info("【onError 出现异常】");
                subscription.cancel();
            }
            @Override
            public void onComplete() {
                log.info("【onComplete 所有数据接收完成】");
            }
        };
        //建立关系 发布者和处理器, 此时处理器扮演 订阅者
        publisher.subscribe(myProcessor);
        //建立关系 处理器和订阅者  此时处理器扮演
        myProcessor.subscribe(subscriber);
        //发布者发布数据
        publisher.submit(1);
        publisher.submit(2);
        publisher.submit(3);
        publisher.submit(4);
        publisher.close();
        TimeUnit.SECONDS.sleep(2);
      }
    }

Xnip20200225_143039.png

 7.总结

この章のデータはJDK9応答フロー特性反応ストリームを説明し、導入された反応ストリームは、背圧、だけでなく、インターフェイスとプロセッサを使用する方法を含んで提供JDK9の反応ストリーム上の2つのユースケースは何かということです。

唯一の4つのインターフェイスに焦点を当てる必要があります、だけでなく、内部JDK9の方法は、コードに対する訴訟は、実際のプロセスは、それは非常に単純な充填でひっくり返す、提供しました!

個人のブログサイトhttps://www.askajohnny.comの訪問を歓迎します!

ブログ記事複数のプラットフォームからこの記事OpenWriteリリース!

公開された21元の記事 ウォンの賞賛0 ビュー2081

おすすめ

転載: blog.csdn.net/qq_34285557/article/details/104569122