Spring Web Reactive | 1. Spring WebFlux | 1.11. WebFlux構成

Web MVC

WebFlux Java構成は、アノテーション付きコントローラーまたは関数型エンドポイントでリクエストを処理するために必要なコンポーネントを宣言し、構成を定義するAPIを提供します。つまり、Java構成によって作成される基盤Beanを理解する必要はありません。それでも詳しく知りたい場合は、WebFluxConfigurationSupportを見るか、特別なBean型についての詳細を読んでください。

構成APIにない高度なカスタマイズには、高度な構成モードを使用して構成を完全に制御できます。

1.11.1. WebFlux構成の有効化

Web MVC

次の例のように、Java configで@EnableWebFluxアノテーションを使用できます。

Java

@Configuration
@EnableWebFlux
public class WebConfig {
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig

上の例では、多数のSpring WebFlux infrastructure beansを登録し、JSONやXMLなど、クラスパスで利用可能な依存関係に適用します。

1.11.2. WebFlux構成API

Web MVC

Java構成では、次の例のようにWebFluxConfigurerインターフェースを実装できます。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    // Implement configuration methods...
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    // Implement configuration methods...
}

1.11.3. 変換とフォーマット(Conversion, formatting)

Web MVC

デフォルトでさまざまな数値および日付形式のフォーマッターが提供され、@NumberFormat@DateTimeFormatを宣言してユーザー定義フォーマッターを指定することもできます。

Java configでカスタムフォーマッターとコンバーターを登録するには、次のようにします。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        // ...
    }

}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addFormatters(registry: FormatterRegistry) {
        // ...
    }
}

デフォルトでは、Spring WebFluxは日付値を解析およびフォーマットするときにリクエストロケールを考慮します。これは、日付が入力フォームフィールドの文字列として表されるフォームで機能します。しかし、「date」と「time」フォームフィールドの場合、ブラウザーはHTML仕様で定義された固定形式を使用します。このような場合、日付と時刻の形式は次のように定義できます。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setUseIsoFormat(true);
        registrar.registerFormatters(registry);
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addFormatters(registry: FormatterRegistry) {
        val registrar = DateTimeFormatterRegistrar()
        registrar.setUseIsoFormat(true)
        registrar.registerFormatters(registry)
    }
}

FormatterRegistrar実装をいつ使用するかについての詳細は、FormatterRegistrar SPIおよびFormattingConversionServiceFactoryBeanを参照してください。

1.11.4. 検証(Validation)

Web MVC

デフォルトでは、Bean Validationがクラスパスに存在する場合(Hibernate Validatorなど)、LocalValidatorFactoryBean@Controllerメソッド引数の@Valid@Validatedで使用するグローバルValidatorとして登録されます。

Java構成では、次の例のようにグローバルValidatorインスタンスを指定できます。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public Validator getValidator(); {
        // ...
    }

}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun getValidator(): Validator {
        // ...
    }

}

次の例のように、Validator実装をローカルに登録できます。

Java

@Controller
public class MyController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(new FooValidator());
    }

}

Kotlin

@Controller
class MyController {

    @InitBinder
    protected fun initBinder(binder: WebDataBinder) {
        binder.addValidators(FooValidator())
    }
}

LocalValidatorFactoryBeanをどこかに注入する必要がある場合は、Beanを作成して@Primaryを宣言し、MVC configで宣言されたものとの競合を避けます。

1.11.5. コンテンツタイプリゾルバー(Content Type Resolvers)

Web MVC

Spring WebFluxでは、リクエストから@Controllerインスタンスの要求メディアタイプを決定する方法を設定できます。デフォルトではAcceptヘッダーのみが確認されますが、クエリパラメーターに基づく解決を有効にできます。

次の例は、要求されたコンテンツタイプの解決をカスタマイズする方法を示しています。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
        // ...
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureContentTypeResolver(builder: RequestedContentTypeResolverBuilder) {
        // ...
    }
}

1.11.6. HTTPメッセージコーデック

Web MVC

次の例は、リクエストおよびレスポンス本文の読み書き方法をカスタマイズする方法を示しています。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.defaultCodecs().maxInMemorySize(512 * 1024);
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
        // ...
    }
}

ServerCodecConfigurerはデフォルトのreaderとwriterのセットを提供します。これを使用してreaderとwriterを追加したり、デフォルトを定義したり、デフォルトを完全に置き換えたりできます。

Jackson JSONとXMLの場合は、Jackson2ObjectMapperBuilderの使用を検討してください。Jackson2ObjectMapperBuilderはJacksonのデフォルトプロパティを次のように定義します。

また、次の既知のモジュールがクラスパスで検出された場合、自動的に登録します。

1.11.7. ビューリゾルバー(View Resolvers)

Web MVC

次の例は、ビューリゾルバーを構成する方法を示しています。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // ...
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        // ...
    }
}

ViewResolverRegistryは、Spring Frameworkと統合されたビュー技術を簡単に登録する方法を提供します。次の例ではFreeMarkerを使用しています(これには基盤となるFreeMarkerビュー技術の構成も必要です)。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.freeMarker();
    }

    // Configure Freemarker...

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("classpath:/templates");
        return configurer;
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.freeMarker()
    }

    // Configure Freemarker...

    @Bean
    fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
        setTemplateLoaderPath("classpath:/templates")
    }
}

次の例のように、ViewResolver実装を登録できます。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        ViewResolver resolver = ... ;
        registry.viewResolver(resolver);
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        val resolver: ViewResolver = ...
        registry.viewResolver(resolver
    }
}

コンテンツネゴシエーション(Content Negotiation)をサポートし、ビューリゾルバー(HTML以外)を通じて他の形式をレンダリングするには、spring-webで利用可能なコーデックのいずれかを受け取るHttpMessageWriterView実装に基づいて、1つ以上のデフォルトビューを構成できます。次の例はその方法を示しています。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.freeMarker();

        Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
        registry.defaultViews(new HttpMessageWriterView(encoder));
    }

    // ...
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {


    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.freeMarker()

        val encoder = Jackson2JsonEncoder()
        registry.defaultViews(HttpMessageWriterView(encoder))
    }

    // ...
}

Spring WebFluxと統合されたビュー技術の詳細は、View Technologiesを参照してください。

1.11.8. 静的リソース(Static Resources)

Web MVC

このオプションは、Resourceベースの場所一覧から静的リソースを提供するための便利な方法を提供します。

次の例では、/resourcesで始まるリクエストを指定すると、相対パスを使用してクラスパスの/staticに関連する静的リソースを探して処理します。ブラウザーキャッシュを最大限に利用し、ブラウザーが行うHTTPリクエストを減らすため、リソースには1年間の保持期間が設定されています。Last-Modifiedヘッダーがある場合はその値を評価し、304ステータスコードが返されます。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
            .addResourceLocations("/public", "classpath:/static/")
            .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
    }

}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public", "classpath:/static/")
                .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
    }
}

リソースハンドラーは、ResourceResolver実装とResourceTransformer実装のチェーンもサポートします。これらを使用して、最適化されたリソースを操作するためのツールチェーンを作成できます。

コンテンツ、固定アプリケーションバージョン、またはその他の情報から計算されたMD5ハッシュに基づくバージョン付きリソースURLには、VersionResourceResolverを使用できます。ContentVersionStrategy(MD5ハッシュ)は、モジュールローダーで使用されるJavaScriptリソースなど、いくつか注意すべき例外がある場合に適しています。

次の例は、Java構成でVersionResourceResolverを使用する方法を示しています。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
    }

}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(VersionResourceResolver().addContentVersionStrategy("/**"))
    }

}

ResourceUrlProviderを使用してURLを書き換え、リゾルバーとトランスフォーマーのチェーン全体を適用できます(たとえば、バージョンを挿入するため)。WebFlux構成はResourceUrlProviderを提供するため、他の場所へ注入できます。

Spring MVCとは異なり、現在のWebFluxにはリゾルバーとトランスフォーマーのノンブロッキングチェーンを使用できるビュー技術がないため、静的リソースURLを透過的に書き換える方法はありません。ローカルリソースのみを提供する場合の回避策は、ResourceUrlProviderを直接(たとえばカスタム要素を通じて)使用してブロックすることです。

EncodedResourceResolver(たとえばGzip、Brotliエンコーディング)とVersionedResourceResolverの両方を使用する場合、エンコードされていないファイルに基づいてコンテンツベースのバージョンが常に安定して計算されるよう、この順序で登録する必要があります。

WebJarsは、org.webjars:webjars-locator-coreライブラリがクラスパスに存在すると自動的に登録されるWebJarsResourceResolverでもサポートされます。リゾルバーはjarバージョンを含むURLを書き換えるとき、バージョンなしの受信URL(たとえば/jquery/jquery.min.jsから/jquery/1.2.0/jquery.min.jsなど)と組み合わせることもできます。

1.11.9. パスマッチング

Web MVC

パスマッチングに関するオプションを設定できます。個々のオプションの詳細は、PathMatchConfigurerのjavadocを参照してください。次の例はPathMatchConfigurerの使用方法を示しています。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
            .setUseCaseSensitiveMatch(true)
            .setUseTrailingSlashMatch(false)
            .addPathPrefix("/api",
                    HandlerTypePredicate.forAnnotation(RestController.class));
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    @Override
    fun configurePathMatch(configurer: PathMatchConfigurer) {
        configurer
            .setUseCaseSensitiveMatch(true)
            .setUseTrailingSlashMatch(false)
            .addPathPrefix("/api",
                    HandlerTypePredicate.forAnnotation(RestController::class.java))
    }
}

Spring WebFluxは、デコードされたパスセグメント値にアクセスし、セミコロンコンテンツ(つまりパス変数または行列変数)を削除するために、RequestPathという解析済みリクエストパス表現を使用します。つまり、Spring MVCとは異なり、リクエストパスをデコードするか、パスマッチングのためにセミコロンコンテンツを削除するかを指定する必要はありません。

Spring WebFluxもSpring MVCとは異なり、サフィックスパターンマッチングをサポートしていません。それに依存しない方向へ移行することが推奨されます。

1.11.10. WebSocketService

WebFlux Java構成は、WebSocketハンドラーの呼び出しをサポートするWebSocketHandlerAdapter Beanを宣言します。つまり、WebSocketハンドシェイクリクエストを処理するために必要なのは、WebSocketHandlerSimpleUrlHandlerMappingを通じてURLへマッピングすることだけです。

場合によっては、WebSocketサーバーのプロパティを構成できるWebSocketServiceを提供し、WebSocketHandlerAdapter Beanを作成する必要があります。たとえば、次のようになります。

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public WebSocketService getWebSocketService() {
        TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
        strategy.setMaxSessionIdleTimeout(0L);
        return new HandshakeWebSocketService(strategy);
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    @Override
    fun webSocketService(): WebSocketService {
        val strategy = TomcatRequestUpgradeStrategy().apply {
            setMaxSessionIdleTimeout(0L)
        }
        return HandshakeWebSocketService(strategy)
    }
}

1.11.11. 高度な構成モード(Advanced Configuration Mode)

Web MVC

@EnableWebFluxDelegatingWebFluxConfigurationをインポートします。

  • WebFluxアプリケーションにデフォルトのSpring設定を提供します。
  • WebFluxConfigurer実装を検出して委譲し、その構成をカスタマイズします。

高度な構成モードの場合、次の例のように、WebFluxConfigurerを実装する代わりに@EnableWebFluxを削除し、DelegatingWebFluxConfigurationを直接拡張できます。

Java

@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {

    // ...
}

Kotlin

@Configuration
class WebConfig : DelegatingWebFluxConfiguration {

    // ...
}

既存のメソッドをWebConfigに保持できますが、基本クラスのBean宣言をオーバーライドすることもでき、クラスパス上に他のWebFluxConfigurer実装をいくつでも置くことができます。