0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

前回の記事「リアクティブプログラミングとは」では、Observable/Observerやオペレーターといった一般的な考え方を整理しました。
本記事では、Javaエコシステムに特化して、Reactive Streams仕様RxJavaProject Reactor(Spring WebFlux) という3つの主要な概念・ライブラリの関係を整理します。
名前が似ていて混同しやすいので、まず全体像を掴むことを目標にします。

全体像:仕様とその実装

Javaのリアクティブ界隈で最初に押さえておきたいのは、「仕様(インターフェースの取り決め)」と「その実装ライブラリ」が別物として存在している、という構造です。

Reactive Streams(仕様)
    ├── java.util.concurrent.Flow(JDK標準、Java 9〜)
    ├── RxJava(ReactiveX系の実装ライブラリ)
    └── Project Reactor(Spring系の実装ライブラリ)

Reactive Streams:ライブラリ間の相互運用のための仕様

Reactive Streamsは、特定のライブラリではなく、「非同期のストリーム処理と、ノンブロッキングなバックプレッシャーをどう扱うか」を定めた 仕様(インターフェースの取り決め) です。PublisherSubscriberSubscriptionProcessorという4つのインターフェースが中核をなします。

この仕様が存在することで、RxJavaで作ったストリームをProject Reactorのコードに渡す、といった異なる実装ライブラリ間の相互運用が可能になります。各ライブラリが独自のインターフェースだけを使っていたら、こうした連携は困難になります。

Java 9からは、この仕様に準拠したインターフェース群がjava.util.concurrent.Flowとして標準ライブラリに取り込まれました。Flow.PublisherFlow.Subscriber等は、Reactive Streams仕様のインターフェースと意味的に1対1で対応しています。

バックプレッシャーとは

Reactive Streams仕様が特に重視しているのが バックプレッシャー(Backpressure) という考え方です。

データの発生源(Publisher)が高速に大量のデータを送り出す一方で、受け取る側(Subscriber)の処理が追いつかない場合、素朴に実装すると受信側にデータが溜まり続け、メモリを圧迫してしまいます。バックプレッシャーは、受信側が「今はこれだけの件数なら処理できる」と発生源に伝え、発生源側もそれに応じて送出量を調整する、双方向の流量制御の仕組みです。受信側が要求した分だけ送出されるため、無制限にデータが溜まり続ける事態を防げます。

RxJava:ReactiveXのJava実装

RxJavaは、リアクティブプログラミングの代表的な実装群である「ReactiveX」のJava(JVM)版です。前回の記事で触れたObservable・オペレーター(mapfilter等)の概念をJavaで使えるようにしたライブラリです。

RxJavaには、バックプレッシャーの有無で使い分ける2種類のストリーム型があります。

バックプレッシャー 主な用途
Observable 非対応 GUIのイベント処理など、短時間・少量のデータストリーム
Flowable 対応 大量データ・ファイルI/O等、送出量の制御が必要な場面

ObservableからFlowableへ変換する際は、あふれた分をどう扱うか(バッファリングする・捨てる・最新のものだけ残す等)をBackpressureStrategyとして明示的に指定する必要があります。

Project Reactor:Spring系のリアクティブライブラリ

Project Reactorは、Reactive Streams仕様を実装した、Spring系フレームワーク(特にSpring WebFlux)で標準的に使われるリアクティブライブラリです。RxJavaと役割は似ていますが、開発元・エコシステムが異なる別のライブラリです。

Project Reactorでは、扱うデータの件数に応じて2種類の型を使い分けます。

送出する要素数
Mono<T> 0件または1件
Flux<T> 0件からN件(複数件の連続したストリーム)

例えば「IDを指定して1件のユーザー情報を取得するAPI」の戻り値はMono<User>、「条件に合う複数件のユーザー一覧を取得するAPI」の戻り値はFlux<User>、というように、返ってくるデータの件数に応じて型を選びます。

Flux<String> names = Flux.just("Alice", "Bob", "Carol")
    .filter(name -> name.startsWith("A") || name.startsWith("B"))
    .map(String::toUpperCase);

names.subscribe(System.out::println);
// ALICE
// BOB

Spring BootでWebFluxを使う場合、spring-boot-starter-webfluxを依存関係に追加すると、内部的にProject Reactor(reactor-core)が組み込まれ、コントローラーのメソッドの戻り値としてMono/Fluxをそのまま返せるようになります。

RxJavaとProject Reactor、どちらを使うべきか

どちらもReactive Streams仕様に準拠しており、考え方(Observable的なストリーム・オペレーターによる宣言的な変換)は共通しています。実務上の選び方の目安は以下の通りです。

  • Spring Boot(特にWebFlux)を使うプロジェクト: Project Reactorが標準で組み込まれているため、素直にReactorを使うのが自然
  • Spring以外のプロジェクト、あるいはAndroid開発: RxJavaの方が情報・実績が豊富で、Android開発では特に広く使われてきた歴史がある
  • 両者ともReactive Streams準拠のため、必要であれば相互に変換して連携させることも可能

まとめ

項目 内容
Reactive Streams 非同期ストリーム処理とバックプレッシャーに関する「仕様」。特定ライブラリではない
java.util.concurrent.Flow Java 9から標準ライブラリに取り込まれた、Reactive Streams準拠のインターフェース群
バックプレッシャー 受信側の処理能力に応じて、送出側がデータ量を調整する双方向の流量制御
RxJava ReactiveXのJava実装。Observable(バックプレッシャー非対応)とFlowable(対応)を使い分ける
Project Reactor Spring系で標準的に使われるリアクティブライブラリ。Mono(0〜1件)とFlux(0〜N件)を使い分ける

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?