素人が理解できるWebFlux、失血を逃した

序文

禿げた頭だけが強くなることができます。
テキストは私のGitHubリポジトリに含まれています。Starへようこそ:https
//github.com/ZhongFuCheng3y/3y

この記事のナレッジポイント構造:

素人が理解できるWebFlux、失血を逃した
ナレッジポイントアーキテクチャ
私のパブリックアカウントの記事をフォローしている学生がいる場合、最近勉強しているので、最近、より良いWebFluxの記事を時々再投稿していることに気付くでしょう。

また、その前に、テクノロジーを学ぶ前に、なぜこのテクノロジーを学ぶ必要があるのか​​を理解する必要があると言いました。実際、今回はWebFluxを学ぶという本来の動機はあまりありませんでした。主な理由は、グループでテクノロジーを共有するために交代で行うため、何を共有すればよいかわかりません...

以前はビッグデータ関連の知識を学んでいましたが、この作品のタイムラインが長くなり、グループでの共有についていけないと感じています(グループのほとんどの学生はビッグデータを理解していて、涙を流しているのは私だけです) 。それで、私が思ったのは、「何か新しいことを学び、それに従事するのはどうですか?」でした。だから私はWebFluxを学ぶのに少し時間を費やしました〜

この記事は主にWebFluxとは何かを説明し、あなたを助けてくれることを願ってドアを案内します(少なくともこの記事を読んだ後、私はWebFluxが何に使用されているかを知っています)

1. WebFluxとは何ですか?

Springの公式ウェブサイトから少し引っ張ると、WebFluxの紹介を見ることができます

素人が理解できるWebFlux、失血を逃した
WebFluxの紹介
公式サイトの紹介からどのような情報が得られますか?

  • 私たちのプログラマーは、さまざまなアプリケーションシナリオに応じてさまざまなテクノロジーを選択することがよくあります。同期ブロッキングに適したシナリオもあれば、非同期非ブロッキングに適したシナリオもあります。また、Spring5は、使用できるリアクティブ(非ブロッキング)テクノロジースタックの完全なセットを提供します(Webコントローラー、アクセス許可制御、データアクセスレイヤーなどを含む)。
  • 左の写真はテクノロジースタックの比較です。
  • レスポンシブタイプは通常、NettyまたはServlet 3.1コンテナを使用します(非同期非ブロッキングがサポートされているため)が、サーブレットテクノロジスタックは
    Web側でサーブレットコンテナを使用し、リアクティブタイプはWebFluxを使用し、サーブレットはSpringMVCを使用します
  • …..
    要約すると、WebFluxは(Webコントロール側の)リアクティブプログラミングの一部にすぎないため、通常、SpringMVCと比較するために使用します。

2.リアクティブプログラミングを理解する方法は?

リアクティブプログラミングについては前述しましたが、WebFluxはリアクティブプログラミングのテクノロジースタックの1つにすぎないため、最初にリアクティブプログラミングとは何かを調べてみましょう。

ウィキペディアから得た定義:

リアクティブプログラミングは、データストリームと変更の伝播に関係する宣言型プログラミングパラダイムです。

リアクティブプログラミングは、データストリームと変更の伝播に基づく宣言的なプログラミングパラダイムです。

ウィキペディアにも小さな例があります:

素人が理解できるWebFlux、失血を逃した
例の
意味おおまかに次のとおりです。

  • 必須プログラミング(毎日のプログラミングモード)では、式a = b + cです。これは、aの値がbとcによって計算されることを意味します。その後bまたはcに変更があった場合、aの値には影響しません。
  • リアクティブプログラミングでは、式a:= b + cは、aの値がbとcによって計算されることを意味します。しかし、その後bまたはcの値が変化すると、aの値に影響します。
    上記の例は、変化の伝播(変化の伝播)を理解するのに役立つと思います

データストリームと宣言をどのように理解しますか?次に、ストリームについて説明します。ラムダ式とストリームストリームに関する記事を以前に書いたことがあります。最初に確認できます。

  • 最近学んだラムダ式の基本

  • このようなストリームストリーミングのラムダ構文を体験してみましょう(ストリームストリーミングの使用には多くのラムダ式が含まれるため、通常は最初にラムダを学び、次にストリームストリーミングを学びます)。

素人が理解できるWebFlux、失血を逃した
文法
ストリームの使用は、3つのステップ(ストリームの作成、中間操作の実行、および最終操作の実行)に分けられます。

素人が理解できるWebFlux、失血を逃した

中間操作の3段階の実装は、実際には、ストリームストリーム(合計/重複排除/フィルタリング)などのデータを操作するための多くのAPIを提供します。

素人が理解できるWebFlux、失血を逃した
中間操作は
非常に多くを説明しました、データフローと宣言を理解する方法は?実際には次のようになります。

  • 元々、データは自分で処理していましたが、後で処理するデータを抽象化して(データストリームに変換)、APIを介してデータストリーム内のデータを(宣言的に)処理しました。たとえば
    、次のコード。データはデータストリームになり、データストリーム内のデータは、明示的に.sum()を呼び出して処理され、最終結果が得られます。
public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum2 = IntStream.of(nums).parallel().sum();
    System.out.println("结果为:" + sum2);
}

以下に示すように:

素人が理解できるWebFlux、失血を逃した
データフローと宣言

2.1リアクティブプログラミング->非同期ノンブロッキング

上記のリアクティブプログラミングとは:

リアクティブプログラミングは、データストリームと変更の伝播に基づく宣言的なプログラミングパラダイムです。

また、データフロー/変更転送/宣言の意味についても説明しましたが、リアクティブプログラミングに関しては、非同期の非ブロッキングは切り離せません。

Springの公式ウェブサイトでのWebFlux情報の紹介から、リアクティブプログラミングは非同期であるため、非同期、ノンブロッキングという言葉を見つけることができます。また、変更の配信は非同期で実行されることも理解できます。

次の図に示すように、合計金額は他の金額の影響を受けます(更新プロセスは非同期です)。

素人が理解できるWebFlux、失血を逃した
合計金額は他の金額の影響を受けます
。JDK8ストリームストリームは同期的であり、リアクティブプログラミングには適していません(ただし、リアクティブストリームプログラミングは操作ストリームであるため、基本的な使用法を理解する必要があります)

リアクティブストリーミングはJDK9ですでにサポートされています。見てみましょう

三、JDK9リアクティブ

レスポンシブストリーミングの仕様はすでに提案されています。

Reactive Streamsは、ノンブロッキングバックプレッシャを使用した非同期ストリーム処理の標準を提供するイニシアチブです-----> http://www.reactive-streams.org/

いくつかの情報を翻訳して追加します。

Reactive Streamsは、エンティティ、インターフェイス、および相互運用性メソッドのセットを定義することにより、非同期の非ブロッキングバックプレッシャーを実現するための標準を提供します。サードパーティはこの標準に従って、Reactor、RxJava、Akka Streams、Ratpackなどの特定のソリューションを実装します。

仕様は実際には4つのインターフェースを定義しています。

素人が理解できるWebFlux、失血を逃した
標準の4つのインターフェイス
Javaプラットフォームは、JDK 9までReactiveの完全なサポートを提供しませんでした。JDK9は、java.util.concurrentパッケージで上記の4つのインターフェイスも定義します。

素人が理解できるWebFlux、失血を逃した
Javaのリアクティブストリームインターフェイスの
一般的なストリーム処理アーキテクチャは、一般的に次のようになります(プロデューサーはデータを生成し、データに対して中間処理を実行し、コンシューマーは消費用のデータを取得します)。

素人が理解できるWebFlux、失血を逃した
ストリーミングアーキテクチャ

  • 一般にプロデューサー(プロデューサー)と呼ばれるデータソース
  • 一般に消費者(消費者)と呼ばれるデータの宛先
  • 処理中に、1つ以上の処理段階がデータに対して実行されます。(プロセッサ)
    ここで、リアクティブストリームのインターフェイスを振り返ると、次のことを理解できるはずです。

  • 出版社(出版社)はプロデューサー(プロデューサー)と同等です
  • サブスクライバー(サブスクライバー)はコンシューマー(コンシューマー)と同等です
  • プロセッサは、パブリッシャーとサブスクライバーの間のデータを処理するために使用されます。
    バックプレッシャ概念は、実際には非常に理解しやすいリアクティブストリームで言及されています。リアクティブストリームでの非同期ノンブロッキングの実現は、プロデューサーとコンシューマーのモデルに基づいており、プロデューサーのコンシューマーに発生しやすい問題は、プロデューサーが生成するデータが多すぎると、コンシューマーが圧倒されることです。

反発は明白です。消費者は生産者に必要なデータ量を伝えることができます。サブスクリプションインターフェイスの機能は次のとおりです。

JDK9インターフェースのメソッドを見て、おそらく上記の内容をよりよく理解しましょう。

// 发布者(生产者)
public interface Publisher<T> {
    public void subscribe(Subscriber<? super T> s);
}
// 订阅者(消费者)
public interface Subscriber<T> {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
}
// 用于发布者与订阅者之间的通信(实现背压:订阅者能够告诉生产者需要多少数据)
public interface Subscription {
    public void request(long n);
    public void cancel();
}
// 用于处理发布者 发布消息后,对消息进行处理,再交由消费者消费
public interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
}

3.1例を見る

コードにはコメントがたくさんあるので、BBはあまり多くありません。コピーして、直接実行することをお勧めします。

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);
    }

}

出力は次のとおりです。

素人が理解できるWebFlux、失血を逃した
出力
プロセスは実際には非常に単純です。

素人が理解できるWebFlux、失血を逃した
プロセス
参照資料:

Java 8のStreamは主にストリームのフィルタリング、マッピング、およびマージに焦点を当てていますが、Reactive Streamはさらに一歩進んで、ストリームの生成と消費、つまり生産と消費者間のストリームの調整に焦点を当てています。

率直に言って、レスポンシブストリーミングは非同期で、ノンブロッキング+フロー制御です(プロデューサーに必要な量/サブスクライブ解除の関係を伝えることができます)

リアクティブプログラミングのシナリオアプリケーションを楽しみにしています:

たとえば、ログ監視システムでは、フロントエンドページがサーバーにデータを継続的に要求し、「コマンドスタイル」のポーリングによって更新する必要がなくなります。代わりに、チャネルが確立された後、データフローはシステムからページに流れ続けます。リアルタイムのインジケーターの変化曲線を示すために、
別の例はソーシャルプラットフォームです。友人のダイナミクス、いいね、コメントは手動で更新されませんが、バックグラウンドデータが変更されると自動的にインターフェイスに反映されます。

第四に、WebFluxを使い始める

たくさん引っ張った後、ようやくWebFluxに戻りました。上記の基礎の後で、私達は今いくつかの結論を引き出すことができます:

  • WebFluxは、Springのリアクティブプログラミングの立ち上げの一部です(Web側)
  • リアクティブプログラミングは非同期で非ブロッキングです(データストリームと変更の伝播に基づく宣言的なプログラミングパラダイム)。
    戻って公式ウェブサイトを見てみましょう

素人が理解できるWebFlux、失血を逃した
mvcまたはwebflux

4.1WebFluxの簡単な体験

Springの公式WebFluxをより速く/スムーズにするために、以前のSpringMVCセットがサポートされました。言い換えれば、SpringMVCのようにWebFluxを使用できます。

素人が理解できるWebFlux、失血を逃した

SpringMVCをサポートするWebFlux使用されるリアクティブストリームは、JDK9プラットフォームを使用しませんが、Reactorと呼ばれるリアクティブストリームライブラリを使用します。したがって、WebFluxの使用を開始するには、実際にはReactorのAPIの使用方法を理解する必要があります。見てみましょう〜

Reactorはリアクティブストリームであり、対応するパブリッシャー(Publisher)もあります。Reactorのパブリッシャーは、次の2つのクラスで表されます。

  • モノラル(0または1要素を返す)
  • フラックス(0-n要素を返す)
    と消費者は私たちが完了するのを助けるための春のフレームワークです

簡単な例(WebFlux環境に基づいて構築)を見てみましょう。

// 阻塞5秒钟
private String createStr() {
    try {
        TimeUnit.SECONDS.sleep(5);
    } catch (InterruptedException e) {
    }
    return "some string";
}

// 普通的SpringMVC方法
@GetMapping("/1")
private String get1() {
    log.info("get1 start");
    String result = createStr();
    log.info("get1 end.");
    return result;
}

// WebFlux(返回的是Mono)
@GetMapping("/2")
private Mono<String> get2() {
    log.info("get2 start");
    Mono<String> result = Mono.fromSupplier(() -> createStr());
    log.info("get2 end.");
    return result;
}

まず、WebFlux環境を構築するとき、アプリケーションサーバーはデフォルトでNettyに設定されていることに注意してください。

素人が理解できるWebFlux、失血を逃した
Nettyに基づいて
、SpringMVCインターフェイスとWebFluxインターフェイスに別々にアクセスして、違いを確認しましょう。

SpringMVC:

素人が理解できるWebFlux、失血を逃した
SpringMVC
WebFlux:

素人が理解できるWebFlux、失血を逃した

呼び出し元(ブラウザー)の観点からは、WebFluxはデータを返す前に5秒間待機する必要があるため、変更を認識しません。ただし、サーバーログから、WebFluxがMonoオブジェクトを直接返すことがわかります(SpringMVCのように5秒間同期的にブロックする代わりに、スレッドが戻ります)。

これがWebFluxの利点です。固定スレッドで高い同時実行性を処理できます(マシンのパフォーマンスを十分に発揮させるため)。

WebFluxはサーバープッシュ(SSE->サーバー送信イベント)もサポートしています。例を見てみましょう。

/**
     * Flux : 返回0-n个元素
     * 注:需要指定MediaType
     * @return
     */
@GetMapping(value = "/3", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
private Flux<String> flux() {
    Flux<String> result = Flux
        .fromStream(IntStream.range(1, 5).mapToObj(i -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
            return "flux data--" + i;
        }));
    return result;
}

その効果は、毎秒データをブラウザにプッシュすることです。

素人が理解できるWebFlux、失血を逃した
サーバープッシュで
WebFluxを書き終えていません。この記事では、開発用のSpringMVCアノテーションをサポートするWebFluxについて説明しています。次の記事では、WebFluxの別のモード(機能エンドポイント)を使用して開発する方法について説明し、いくつかの一般的な問題を追加する必要があります〜

「インタビューの質問」、「基本」、「上級」の2年間の骨の折れる記事がすべてここにあります!

素人が理解できるWebFlux、失血を逃した
300以上のオリジナル記事技術記事
膨大なビデオリソース
絶妙なマインドマップ
顔の質問
プレススキャンコードは、
視聴と共有の取得について懸念している可能性があります私にとって非常に重要です!
作成するのは簡単ではありません。あなたのサポートと認識が私の作成の最大の動機です。次の記事でお会いしましょう!いいねと注意を求める️メッセージを共有して残すことを求める

おすすめ

転載: blog.51cto.com/15082392/2590299