Spring WebFluxってなんだ? って感じだったんで https://docs.spring.io/spring/docs/5.0.3.RELEASE/spring-framework-reference/web-reactive.html を読んでテキトーに訳した。なおマッタクといっていいほど推敲してないです。
Web on Reactive Stack
このパートでは、Netty, Undertow, Servlet 3.1+コンテナなどノンブロッキングサーバ上で動作するReactive Streams APIでwebアプリケーションを構築する、リアクティブスタック(reactive stack)について解説します。Spring WebFluxフレームワーク、リアクティブWebClient、Testing、についてのチャプターがあります。ServletスタックについてはWeb on Servlet Stackを参照してください。
1. Spring WebFlux
1.1. Introduction
Spring Frameworkに含まれるSpring Web MVCはServlet APIとServletコンテナ向けに作られました。リアクティブスタックのwebフレームワークWebFluxはversion 5.0で後から追加されました。完全にノンブロッキングで、Reactive Streamsのバックプレッシャをサポートし、Netty, Undertow, Servlet 3.1+コンテナなどのサーバ上で動作します。
spring-webmvcとspring-webfluxとソースモジュール名は似たものなっており、Spring Frameworkで共存しています。各モジュールはオプショナルです。アプリケーションはどちらか一方を使ってもよいし、両方使っても構いません。たとえば、Spring MVCのcontrollerをリアクティブなWebClientにするなど。
1.1.1. Why a new web framework?
理由の一つは、少数のスレッドで並行処理し、少ないハードウェアリソースでスケールする、ノンブロッキングなwebスタックに対するニーズです。Servlet 3.1はノンブロッキングI/OのAPIを提供しました。しかし、これを利用すると、同期(Fileter, Servlet)やブロッキング(getParameter, getPart)を契約とするServlet APIの部分から離れることになります。これが何らかのノンブロッキングランタイムの基盤として振る舞う新しい共通APIが求められた背景です。Nettyなどのサーバは非同期・ノンブロッキング空間で確立するのでこのことは重要です。
もう一つの理由は関数型プログラミングです。Java 5で追加されたアノテーションが、アノテーションベースのRESTコントローラーやユニットテストなど、新たな可能性を切り開いたように、Java 8のラムダ式追加は関数型APIの可能性を開きました。これらは、CompletableFutureとReactiveXで一般的となった、ノンブロッキングアプリケーションとcontinuation style APIに恩恵を与えました。これらでは非同期ロジックの宣言的なコンポジションが可能です。プログラミングモデルのレベルでは、Java 8によって、Spring WebFluxはコントローラと共にファンクショナルなwebエンドポイントを提供できるようになりました。
1.1.2. Reactive: what and why?
ノンブロッキングとファンクショナルについては上記で触れましたが、リアクティブの理由とその意味については以下で説明します。
リアクティブ""reactive")という用語は、I/Oイベントに反応するネットワークコンポーネント、マウスイベントに反応するUIコントローラーなど、変更に対する反応で構築するプログラミングモデルを指します。そういう意味でノンブロッキングはリアクティブで、操作完了やデータ到着など、ブロッキングではなく通知に反応するモードを使用します。 また、Springチームが"リアクティブ"と関連付けたもう一つの重要なメカニズムにノンブロッキングのバックプレッシャがあります。非同期・命令型(imperative code)・ブロッキングの呼び出しでは、バックプレッシャは呼び出し元に待機を自然と強制する形になります。ノンブロッキングでは、イベントのレート制御が重要で、これは高速なプロデューサーがその宛先(destination)を溢れさせないようにするためです。
Reactive Streamsの仕様は小さく(small spec)、Java 9で採用*1され、非同期コンポーネントとバックプレッシャ間の相互作用を定義しています。たとえばデータリポジトリ(data repository)は、Publisherとしての振る舞いはHTTPサーバのデータをプロデュースし、それからSubscriberとしての振る舞いはレスポンスを書き込みます。パプリッシャのデータプロデュースを、サブスクライバでどのくらい高速or低速に制御させるか、がReactive Streamsの主目的となります。
Common question: パブリッシャがスローダウン出来ない場合は?
eactive Streamsの目的は、あくまでも、メカニズムと境界を確立するものです。パブリッシャがスローダウン出来ない場合、バッファリング・廃棄・失敗、するかどうかを決定します。
1.1.3. Reactive API
Reactive Streamは相互運用性(interoperability)で重要な役割を担います。ライブラリと基盤コンポーネントに関心事が存在し、低レベルなのでアプリケーションAPIとしてはあまり有用ではありません。アプリケーションは、Java 8のStream APIのようだがコレクションに限定しない、非同期ロジックをまとめる関数型のAPIという高レベルでリッチなAPIを必要とします。リアクティブのライブラリの役割はこれです。
Spring WebFluxはリアクティブのライブラリにRactorを使用します。
ReactiveXのvocabulary of operatorsで定められた豊富な演算子で0..1および0..Nのデータシーケンスを動作させるMonoとFlux APIがあります。ReactorはReactive Streamsのライブラリなので演算子はすべてノンブロッキングのバックプレッシャをサポートします。ReactorはサーバーサイドJavaを強く意識しており、Springと密に意見交換しながら開発されています。
WebFluxはコア依存性としてReactorを要求しますが、Reactive Streams経由で別のリアクティブライブラリとの相互運用性が存在します。通常、WebFlux APIは入力にプレーンなPublisherを取り、内部的にReactor型に変換して使用し、出力にFluxかMonoのどちらかを返します。入力に何らかのPublisherを渡して出力で操作を適用できますが、それとは別のリアクティブライブラリでこれを使うには出力を変換する必要があります。変換可能な場合であれば、たとえばアノテーションを付与したコントローラーでは、WebFluxはRxJavaもしくはその他のリアクティブライブラリに透過的に変換します。
1.1.4. Programming models
spring-webモジュールにはリアクティブの基礎部分が含まれ、これにはHTTPの抽象化を含むSpring WebFlux、サポートするサーバ向けのReactive Streamsアダプタ、コーデック、Servlet API相当(ただしノンブロッキング)のコアWebHandler API、があります。
これら基礎部分の上にSpring WebFluxは二つのプログラミングモデルを提供しています。
- アノテーション付与のコントローラ -
spring-webモジュールのアノテーションを用いてSpring MVCと整合性を保つモデル。Spring MVCとWebFluxのコントローラは共にリアクティブの戻り値型をサポートするので、見た目上では区別がしづらいです。目立つ違いとしてはWebFluxはリアクティブな@RequestBody引数をサポートします。 - ファンクショナルエンドポイント(Functional Endpoints) - *2ラムダベースの軽量な関数型プログラミングモデル。アプリケーションがルーティングもしくはリクエスト処理に使用する、小さいライブラリあるいはユーティリティ群と見なせます。アノテーション付与のコントローラとの大きな違いは、アプリケーションがリクエストの開始から終了までの一連の処理となるか、アノテーションとコールバックで何らかのやりたい事を宣言するか、にあります。
1.1.5. Choosing a web framework
Spring MVCとWebFluxのどちらを選べば良いか。いくつかの異なる視点から見ていきます。
既に稼働中のSpring MVCアプリケーションがある場合、何も変える必要はありません。命令型プログラミングは、書きやすく、理解しやすくて、デバッグもしやすいです。歴史的に大半のライブラリはブロッキングなので過去の資産を最大限生かせます。
既にノンブロッキングのwebスタックの採用経験がある場合、 Spring WebFluxからそこのwbスタックと同一の実行モデルによる利点が得られます。また、サーバの選択肢、Netty, Tomcat, Jetty, Undertow, Servlet 3.1+コンテナ、プログラミングモデルの選択肢、アノテーション付与のコントローラとファンクショナルエンドポイント、リアクティブライブラリの選択肢、Reactor, RxJava, など、があります。
Java 8のラムダやKotlinで使うための軽量な関数型webフレームワークに関心がある場合はSpring WebFluxのファンクショナルエンドポイントを使います。小規模アプリケーションか、透過性と制御性で要求の複雑さを抑えるマイクロサービスでの選択肢の一つになります。
マイクロサービスアーキテクチャでは、 Spring MVCもしくはSpring WebFluxのコントローラを使うアプリケーションを混在するか、Spring WebFluxのファンクショナルエンドポイントを用います。両方のフレームワークとも同じアノテーションベースのプログラミングモデルをサポートしているので知識の再利用はしやすいです。ただし妙な使い方をしない場合に限る*3。
アプリケーションを評価する方法の一つは依存性を調べることです。ブロッキングの永続化API(JPA, JDBC)や、ネットワークAPIがある場合、少なくともSpring MVCは良くあるアーキテクチャ向けに最適です。技術的には、ReactorもRxJavaも異なるスレッドでブロッキングAPIを実行することで適応可能ですが、ノンブロッキングwebスタックを最大限活用しているとは言えません。
Spring MVCアプリケーションでリモートサービス呼び出しがある場合、リアクティブのWebClientを検討してください。Spring MVCのコントローラメソッドで直接リアクティブの型(Reactor, RxJava, その他)を返せます。呼び出しごとのレイテンシや、呼び出し間の相互依存性が大きいほど、大きなメリットを得られます。Spring MVCのコントローラは同様にその他のリアクティブコンポーネントも呼び出せます。
大規模チームの場合、ノンブロッキング・関数型・宣言的プログラミングに移行する際の急激な学習曲線に気を付けてください。完全には移行しない現実的な方法としてリアクティブのWebClientから始めるものがあります。スモールスタートの後に効果を測定してください。我々の想定では、アプリケーションの大部分を移行する必要は無い、と考えています。
今一つメリットが分からない場合、ノンブロッキングI/Oの動作と効果を知る事から始めてください(例:シングルスレッドNode.jsの並行処理、は矛盾してるわけではありません)。"scale with less hardware"はキャッチフレーズで何らかの効果を保証するものではないし、スローダウンしたり予測不能なネットワークI/Oが無いわけでは無いです。Netflixのblog postが好例です。
1.1.6. Choosing a server
Spring WebFluxはNetty, Undertow, Tomcat, Jetty, Servlet 3.1+コンテナでサポートしています。サーバは共通のReactive Streams APIに対応しています。Spring WebFluxのプログラミングモデルはその共通API上に作られています。
Common question: 両方のスタックでTomcatとJettyを使うには
TomcatとJettyのコアはノンブロッキングです。ブロッキングファサードを追加するServlet APIがそれに当たります。3.1からServlet APIはノンブロッキングI/Oを追加しています。ただし、同期やブロッキングを避ける必要があります。そのため、SpringのリアクティブwebスタックにはReactive Streamsとブリッジする低レベルなServletアダプタがありますが、Servlet APIを直接使う方法は公開していません。
Spring Boot 2はデフォルトではWebFluxを使用し、これはNettyが非同期・ノンブロッキングで広く使われており、また、クライアントとサーバの両方でリソースを共有できます。Nettyと比較するとServlet 3.1のノンブロッキングI/Oは、敷居が高いため、あまり使われていません。Spring WebFluxは導入の糸口となります。
Spring Bootのデフォルトサーバはすぐに使い始めるための意味合いが強いです。アプリケーションでは、パフォーマンス最適化・完全ノンブロッキング・Reactive Streamsバックプレッシャに変換、を行うその他のサーバを選択可能です。Spring Bootで別のサーバにスイッチするのは簡単です。
1.1.7. Performance vs scale
Performanceは様々な特徴と意味合いを持っています。Reactiveとノンブロッキングは基本的にはアプリケーションを高速にはしません。例えば、WebClientでパラレルにリモート呼び出しを実行すると、高速になる場合があります。一般論として、ノンブロッキング化には別途の開発が必要で、処理時間が少々上昇する可能性があります。
リアクティブとノンブロッキングに期待されるメリットは、小規模・固定スレッド数・省メモリでスケールする能力です。これにより、アプリケーションは予測可能な方法でスケールするので負荷に弾力性を持つようになります。ただし、これらの利点が活きるには、低速で予測不能なネットワークI/Oの混在するレイテンシの場合です。そういう場所ではリアクティブスタックは強靭さを発揮し、劇的な違いを見せるでしょう。
1.2. Reactive Spring Web
spring-webモジュールには、リアクティブwebアプリケーションを構築するための、クライアントとサーバ双方の、低レベル基盤とHTTP抽象化があります。実装にReactorを使用するReactive Streams上にすべてのpubli APIは構築されています。
サーバは二つのレイヤーに分けられます。
- HttpHandlerとサーバアダプタ。Reactive StreamsバックプレッシャでHTTPリクエストを処理する、最も基本的な共通API。
- WebHandler API - やや高レベルなフィルターチェーンで処理をする汎用サーバweb API。
1.2.1. HttpHandler
HTTPサーバはHTTPリクエストを処理するための何らかのAPIを備えています。HttpHandlerは、リクエストとレスポンスを処理する一つのメソッドからなる、シンプルな契約(simple contract)です。このAPIは意図的に小さくしています。その主な用途は、異なるサーバでHTTPリクエストを処理するReactive StreamsベースのAPIという、汎用部品の提供です。
spring-webモジュールにはサポート対象サーバ別のアダプタが含まれます。以下の表は使用されるサーバAPIとReactive Streamsのサポート方法です。
| Server name | Server API used | Reactive Streams support |
|---|---|---|
| Netty | Netty API | Reactor Netty |
| Undertow | Undertow API | spring-web: Undertow to Reactive Streams bridge |
| Tomcat | Servlet 3.1 non-blocking I/O; Tomcat API to read and write ByteBuffers vs byte | spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge |
| Jetty | Servlet 3.1 non-blocking I/O; Jetty API to write ByteBuffers vs byte | spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge |
| Servlet 3.1 container | Servlet 3.1 non-blocking I/O | spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge |
以下は必要となる依存性、サポートバージョン、各サーバ別のコード例です。
| Server name | Group id | Artifact name |
|---|---|---|
| Reactor Netty | io.projectreactor.ipc | reactor-netty |
| Undertow | io.undertow | undertow-core |
| Tomcat | org.apache.tomcat.embed | tomcat-embed-core |
| Jetty | org.eclipse.jetty | jetty-server, jetty-servlet |
Reactor Netty:
HttpHandler handler = ... ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler); HttpServer.create(host, port).newHandler(adapter).block();
Undertow:
HttpHandler handler = ... UndertowHttpHandlerAdapter adapter = new UndertowHttpHandlerAdapter(handler); Undertow server = Undertow.builder().addHttpListener(port, host).setHandler(adapter).build(); server.start();
HttpHandler handler = ... Servlet servlet = new TomcatHttpHandlerAdapter(handler); Tomcat server = new Tomcat(); File base = new File(System.getProperty("java.io.tmpdir")); Context rootContext = server.addContext("", base.getAbsolutePath()); Tomcat.addServlet(rootContext, "main", servlet); rootContext.addServletMappingDecoded("/", "main"); server.setHost(host); server.setPort(port); server.start();
Jetty:
HttpHandler handler = ... Servlet servlet = new JettyHttpHandlerAdapter(handler); Server server = new Server(); ServletContextHandler contextHandler = new ServletContextHandler(server, ""); contextHandler.addServlet(new ServletHolder(servlet), "/"); contextHandler.start(); ServerConnector connector = new ServerConnector(server); connector.setHost(host); connector.setPort(port); server.addConnector(connector); server.start();
Servlet 3.1+コンテナにWARとしてデプロイするには、ServletHttpHandlerAdapterでHttpHandlerをラップして、Servletとして登録します。AbstractReactiveWebInitializerを使用する場合は自動的に行われます。
1.2.2. WebHandler API
HttpHandlerは異なるHTTPサーバ上で動かすための最も低レベルな契約です。これの上の、WebHandler APIはそれより少し上のレベルですが、WebExceptionHandler's, WebFilter's, WebHandlerのチェーンを形成する汎用用途のコンポーネント群になります。
WebHandler APIのすべてのコンポーネントは入力にServerWebExchangeを取り、このクラスの裏では、リクエスト変数・セッション変数・パースしたフォームデータへのアクセス・マルチパートなど、webアプリケーションで使用する構成要素を提供するためのServerHttpRequestとServerHttpResponseが存在します。
WebHttpHandlerBuilderはリクエスト処理チェーンをアセンブルするのに使われます。コンポーネントを手動で追加するにはこのビルダーを使うか、たいていはSpringのApplicationContextから取得することになるHttpHandlerは、サーバアダプタ経由の実行準備が出来た状態で取得できます。
ApplicationContext context = ...
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context).build()
以下の表はWebHttpHandlerBuilderが検出するコンポーネントのリストです。
| Bean name | Bean type | Count | Description |
|---|---|---|---|
| WebExceptionHandler | 0..N | すべてのWebFilterとそのターゲットWebHandlerの後に適用する例外ハンドラ |
|
| WebFilter | 0..N | ターゲットWebHandlerの前後で実行するフィルタ |
|
| "webHandler" | WebHandler | 1 | リクエストハンドラ |
| "webSessionManager" | WebSessionManager | 0..1 | ServerWebExchangeのメソッド経由で公開されるWebSession用のマネージャ。デフォルトはDefaultWebSessionManager |
| "serverCodecConfigurer" | ServerCodecConfigurer | 0..1 | フォームとマルチパートをパースするHttpMessageReaderにアクセスする時に使う。ServerWebExchangeのメソッド経由で公開される。デフォルトはServerCodecConfigurer.create() |
| "localeContextResolver" | LocaleContextResolver | 0..1 | ServerWebExchangeのメソッド経由で公開されるLocaleContext用のリゾルバ。デフォルトはAcceptHeaderLocaleContextResolver |
Form Reader
ServerWebExchangeはフォームデータにアクセスする以下の公開メソッドがあります。
Mono<MultiValueMap<String, String>> getFormData();
DefaultServerWebExchangeは設定されているHttpMessageReaderでフォームデータ("application/x-www-form-urlencoded")をMultiValueMapにパースします。デフォルトではFormHttpMessageReaderはServerCodecConfigurerのbeanを使用して設定されます。(Web Handler API参照)
Multipart Reader
ServerWebExchangeはマルチパートにアクセルする以下の公開メソッドがあります。
Mono<MultiValueMap<String, Part>> getMultipartData();
DefaultServerWebExchangeは設定されているHttpMessageReader<MultiValueMap<String, Part>>で"multipart/form-data"をMultiValueMapにパースします。現状、サポートされているサードパーティライブラリはSynchronoss NIO Multipartだけで、我々の知る限りではこのライブラリはマルチパートリクエストのノンブロッキングなパースが出来ます。ServerCodecConfigurerのbeanを通して有効化します。(Web Handler API)
ストリーミングのマルチパートをパースするには、HttpMessageReader<Part>から返されるFlux<Part>を代わりに使います。たとえば、@RequestPartを使うコントローラーはnameとパートが対応するMapライクのアクセスを意味し、そのため、完全なマルチパートのパースが必要になります。対照的に、Flux<Part>のコンテンツをデコードするのに@RequestBodyを使用可能で、その際MultiValueMapを生成しません。
1.2.3. HTTP Message Codecs
spring-webモジュールはRective StreamsのPublisherを介してHTTPのリクエストとレスポンスボディのエンコードとデコードをするためのHttpMessageReaderとHttpMessageWriterを定義しています。これらはクライアント側で使うものでは例えばWebClient、サーバ側ではアノテーションを付与するコントローラとファンクショナルエンドポイントで使います。
spring-coreモジュールはEncoderとDecoderを定義しており、これらはHTTPに非依存で、NettyのByteBufとjava.nio.ByteBufferなど異なるバイトバッファ表現を抽象化するDataBufferを使用します(Buffers and Codecsを参照)。EncoderはHttpMessageWriterとして使うためにEncoderHttpMessageWriterでラップ可能で、DecoderはHttpMessageReaderとして使うためにDecoderHttpMessageReaderでラップ可能です。
spring-coreモジュールには、byte[], ByteBuffer, DataBuffer, Resource, String、で使う基本的なEncoderとDecoderの実装があります。spring-webモジュールにはJackson JSON, Jackson Smile, JAXB2で使うEncoderとDecoderを追加しています。また、spring-webモジュールには、server-sentイベント、フォームデータ、マルチパートリクエストで使うweb固有のreaderとwriterがあります。
アプリケーションで使うためにreaderとwriterを設定したりカスタマイズするには、基本的にはClientCodecConfigurerかServerCodecConfigurerを使います。
Jackson JSON
decoderはバイトのチャンクストリームをTokenBufferストリームへパースするのにJacksonのノンブロッキングなバイト配列パーサーを用います。これはJacksonのObjectMapperに変換できます。
encoderは以下のようにPublisher<?>を処理します。
PublisherがMono(つまり単一の値)の場合、値はJSONにエンコードされる。- メディアタイプが
application/stream+jsonの場合、Publisherが生成するそれぞれの値はJSONに改行つきでエンコードされます。 - 上記以外の場合、
Publisherのすべての中身はFlux#collectToList()に集約され、このコレクションがJSON配列にエンコードされます。
上記ルールの特殊ケースに、ServerSentEventHttpMessageWriterは入力のPublisherの内容をそれぞれMono<?>としてJackson2JsonEncoderに送ります。
注意点として、Jackson JSON encoderとdecoderはString型のレンダリング要素を明示的に返します。Instead String's are treated as low level content, (i.e. serialized JSON) and are rendered as-is by the CharSequenceEncoder.*4 JSON配列としてレンダリングされるFlux<String>にしたい場合、Flux#collectToList()を使用してMono<List<String>>にします。
1.3. DispatcherHandler
Spring WebFluxやSpring MVCはfront controller patternで設計されており、その中心にあるWebHandlerやDispatcherHandlerは、リクエスト処理に共通なアルゴリズムがあり、実際の動作は設定可能でコンポーネントに処理を委譲します。このモデルは柔軟性があり多用な処理の流れに対応できます。
DispatcherHandlerはコンポーネントに処理を委譲し、委譲先はSpringのconfigurationから取得します。また、それ自身もSpringのbeanで、このbeanを実行するcontextにアクセスするためにApplicationContextAwareを実装しています。DispatcherHandlerはbean名"webHandler"で宣言されているので、これによってWebHttpHandlerBuilderでwebHandlerが参照可能となり、WebHandler APIで解説したリクエスト処理チェーンとの結びつけを行います。
WebFluxアプリケーションのSpring configurationは基本的には以下があります。
- bean名"webHandler"の
DispatcherHandler WebFilterとWebExceptionHandlerのbean- DispatcherHandler special beans
- その他
処理のチェーンを構築するためにWebHttpHandlerBuilderにconfigurationが渡されます。
ApplicationContext context = ...
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context);
戻り値HttpHandlerはerver adapterで使える状態になっています。
1.3.1. Special bean types
DispatcherHandlerはリクエスト処理と適切なレスポンスレンダリングに別のbeanへ委譲します。Springマネージドオブジェクトインスタンスは以下表のフレームワークのクラスの一つを実装します。SpringのWebFluxはそうしたクラスのビルトイン実装を提供しており、カスタマイズ・拡張・置換も可能です。
| Bean type | Explanation |
|---|---|
| HandlerMapping | リクエストとハンドラのマッピング。マッピングは何らかの基準をベースにするもので、HandlerMappingの実装に依ります。アノテーションを付与するコントローラー、シンプルなURLパターンマッピング、など。メインとなる HandlerMapping実装は、@RequestMappingを付与するメソッドに基づくRequestMappingHandlerMapping、ファンクショナルエンドポイントのルーティングに基づくRouterFunctionMapping、ハンドラにURLパスパターンを明示的に登録するSimpleUrlHandlerMapping、があります。 |
| HandlerAdapter | リクエストにマッピングされているハンドラを呼び出すDispatcherHandlerのヘルパーです。ハンドラ呼び出しの実装に無関係の処理が担当です。例えば、コントローラ呼び出し時に必要となるアノテーション解決などです。HandlerAdapterの主な用途はそういた詳細をDispatcherHandlerから分離することです。 |
| HandlerResultHandler | ハンドラ呼び出し結果を処理してレスポンスを確定します。 ビルトインの HandlerResultHandler実装は、戻り値ResponseEntityのResponseEntityResultHandler、@ResponseBodyメソッドのResponseBodyResultHandler、ファンクショナルエンドポイントが返すServerResponseのServerResponseResultHandler、viewとmodelでレンダリングするViewResolutionResultHandler、があります。 |
1.3.2. Framework Config
DispatcherHandlerはApplicationContext内で自身が必要とするbeanを検出します。アプリケーションで必要に応じてそうしたbeanを宣言します。ただし、WebFluxのJava configは高レベルのAPIを設定済みで、ここに必要なbean宣言がしてあるので、これを起点に出来ます。詳細はWebFlux Configを参照してください。
1.3.3. Processing
DispatcherHandlerは以下のようにリクエストを処理します。
HandlerMappingそれぞれにハンドラマッチングを問い合わせ、最初にマッチしたものが使われる。- マッチするハンドラがある場合、適当な
HandlerAdapterを介してハンドラを実行し、HandlerResultで実行結果を返す。 HandlerResultHandlerにHandlerResultが与えられます。HandlerResultHandlerは処理を完了させるためのもので、レスポンスに直接書き込んだり、レンダリングするビューを使用したりします。