Spring Boot で @EnableWebFlux 付与していたら WebFlux から静的リソースを配布できなかった

## 結論

Spring Boot 2.3.4.RELEASE時点でSpring WebFluxを使用する場合、
`@EnableWebFlux`アノテーションを使用すると静的リソースを配布できなくなります。

## あらまし

数年ぶりにWEBサーバーを開発することになった。
JavaもWEBサーバーの開発も久しぶりなので情報が多いSpinrg Bootを使用することにした。

暫くJavaを使用していなかった間にSpring FrameworkにはSpring WebFluxが追加されていたので、
せっかくなのでWebFluxを使用することにした。

初めて使用するSpring WebFluxのドキュメントを軽く読んだ後、
Spring Bootでアプリケーションを自動構成した。

この時点ではWebFluxの利用に大きな問題はなかったが、後から静的リソースを配布する必要が出てきた。

Spring BootでWebFluxが構成されていればSpring MVCと同様に静的リソースを配布できるらしい。
`classpath:/static/`にリソースを配置し、WEBブラウザでアクセスをすればサーバーからレスポンスが返ってくると思っていたが、404 Not Foundが返ってくる。

何かを間違えているのかと思いSpring Bootのドキュメントを閲覧するが、[出来ると書かれている](https://docs.spring.io/spring-boot/docs/2.3.4.RELEASE/reference/htmlsingle/#boot-features-webflux-auto-configuration)。

ドキュメントでは可能と書かれている静的リソースが配布されない。
理由がいまいちわからなかったため、Spring BootのWebFlux関係のauto-configurationを確認する。

WebFluxで静的リソースを配布するための構成を探して[WebFluxAutoConfiguration](
https://github.com/spring-projects/spring-boot/blob/v2.3.4.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java)を発見した。

`WebFluxConfig#addResourceHandlers(ResourceHandlerRegistry)`で静的リソースのマッピングを追加しているようなので、
`WebFluxConfig#addResourceHandlers(ResourceHandlerRegistry)`と`WebFlux`コンストラクタの2か所にブレークポイントを追加し、
デバッガーをアタッチしてアプリケーションを起動する。
しかし、アプリケーションが起動し終わってもブレークポイントがヒットしなかった。

Spring Bootのauto-configurationが呼び出されないときは、大抵は`@Bean`の不足やライブラリの不足でauto-configurationが実行される条件が満たされない状態が発生している。

何か自分が見落としているんだろうと思いながら改めてSpring Bootのドキュメントを眺めていると、
ドキュメントに原因がはっきりと書かれていることに気が付いた。

## 原因

Spring BootはWebFluxの構成を`WebFluxAutoConfiguration`で実施している。
このクラスには`@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })`が付与されているため、
他に`WebFluxConfigurationSupport`の実装が`@Bean`登録されているとこのauto-configurationは実行されなくなってしまう。

`@EnableWebFlux`の[定義を確認](https://github.com/spring-projects/spring-framework/blob/69921b49a5836e412ffcd1ea2c7e20d41f0c0fd6/spring-webflux/src/main/java/org/springframework/web/reactive/config/EnableWebFlux.java#L90)すると
`@Import(DelegatingWebFluxConfiguration.class)`が付与されている。
`DelegatingWebFluxConfiguration`は`WebFluxConfigurationSupport`の実装にあたるので、
Spring Bootが用意している`WebFluxAutoConfiguration`は`ConditionalOnMissingBean`によってauto-configurationとして動作しなくなる。

最初に読んだSpring WebFluxのドキュメントで`@Configuration`クラスに`@EnableWebFlux`を付与していたので
WebFluxアプリケーションを実装するためには付与しないといけないと思い込んでいた。

しかし、Spring BootはWebFluxに機能を追加するために独自の`WebFluxConfigurationSupport`を提供しているため、
Spring BootでWebFluxを有効化するときは`@EnableWebFlux`を付与してはいけないというルールがあった。

このあたりの仕様はSpring Bootのドキュメントにしっかりと[書かれていた](https://docs.spring.io/spring-boot/docs/2.3.4.RELEASE/reference/htmlsingle/#boot-features-webflux-auto-configuration)のだが、
Spring WebFluxのドキュメント読んだ後だったので読み飛ばしてしまっていた。

## 余談

Spring Bootはクラスパスのライブラリを検出してSpring MVCとSpring WebFluxのどちらをWEBサーバーとして構成するか決定している。

では、Spring MVCとSpring WebFluxの両方のライブラリがクラスパスに存在するとき、
どうやって有効化するWEBサーバーをコントロールできるのか、
念のために調べたところSpring Bootのプロパティ`spring.main.web-application-type`に`REACTIVE`を指定して
[WebFluxでアプリケーションを構成することが出来るようだ](https://github.com/spring-projects/spring-boot/issues/22162)。

`spring.main.web-application-type`の設定状態の判定は、
`WebFluxAutoConfiguration`に付与されている`@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)`アノテーションで行われている。

Spring MVCが使いたければ`spring.main.web-application-type`に`SERVLET`を指定する。