Spring Web Reactive | 1. Spring WebFlux | 1.11. WebFlux Config
WebFlux Java configuration provides an API for declaring the components and defining the configuration required to process requests with annotated controllers or functional endpoints. In other words, you do not need to understand the underlying beans created by Java configuration. If you still want to understand more, see WebFluxConfigurationSupport or read more about special bean types.
For advanced customizations not available in the configuration API, use advanced configuration mode to take full control of the configuration.
1.11.1. Enable WebFlux Configuration
You can use the @EnableWebFlux annotation in Java config, as shown in the following example.
Java
@Configuration
@EnableWebFlux
public class WebConfig {
}
Kotlin
@Configuration
@EnableWebFlux
class WebConfig
The preceding example registers a number of Spring WebFlux infrastructure beans and adapts to dependencies available on the classpath, such as JSON and XML.
1.11.2. WebFlux Configuration API
Java configuration can implement the WebFluxConfigurer interface, as shown in the following example.
Java
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
// Implement configuration methods...
}
Kotlin
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
// Implement configuration methods...
}
1.11.3. Conversion and Formatting
By default, formatters for various number and date formats are provided, and you can also declare @NumberFormat and @DateTimeFormat to specify custom formatters.
To register custom formatters and converters in Java config, do the following.
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) {
// ...
}
}
By default, Spring WebFlux takes the request locale into account when parsing and formatting date values. This works for forms where dates are represented as strings in input fields. However, for date and time form fields, browsers use fixed formats defined by the HTML specification. In such cases, date and time formats can be defined as follows.
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)
}
}
For details on when to use
FormatterRegistrarimplementations, seeFormatterRegistrarSPI andFormattingConversionServiceFactoryBean.
1.11.4. Validation
By default, if Bean Validation is present on the classpath, such as Hibernate Validator, LocalValidatorFactoryBean is registered as the global Validator for use with @Valid and @Validated on @Controller method arguments.
Java configuration can specify a global Validator instance, as shown in the following example.
Java
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public Validator getValidator(); {
// ...
}
}
Kotlin
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun getValidator(): Validator {
// ...
}
}
You can register a Validator implementation locally, as shown in the following example.
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())
}
}
If you need to inject
LocalValidatorFactoryBeansomewhere, create a bean and declare@Primaryto avoid conflicts with the one declared by MVC config.
1.11.5. Content Type Resolvers
Spring WebFlux lets you configure how the requested media type is determined for @Controller instances from a request. By default, only the Accept header is checked, but query-parameter-based resolution can be enabled.
The following example shows how to customize requested content type resolution.
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 Message Codecs
The following example shows how to customize reading and writing request and response bodies.
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 provides a default set of readers and writers. You can use it to add readers and writers, customize defaults, or completely replace the defaults.
For Jackson JSON and XML, consider using Jackson2ObjectMapperBuilder. Jackson2ObjectMapperBuilder defines Jackson default properties as follows.
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIESis disabled.MapperFeature.DEFAULT_VIEW_INCLUSIONis disabled.
It also automatically registers the following known modules if they are detected on the classpath.
jackson-datatype-joda: Supports Joda-Time types.jackson-datatype-jsr310: Supports Java 8 Date and Time API types.jackson-datatype-jdk8: Supports other Java 8 types such asOptional.jackson-module-kotlin: Supports Kotlin classes and data classes.
1.11.7. View Resolvers
The following example shows how to configure view resolvers.
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 provides a simple way to register view technologies integrated with the Spring Framework. The following example uses FreeMarker, which also requires configuration of the underlying FreeMarker view technology.
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")
}
}
You can register a ViewResolver implementation as shown in the following example.
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
}
}
To support content negotiation and render other formats through view resolvers, beyond HTML, you can configure one or more default views based on the HttpMessageWriterView implementation, which accepts one of the codecs available in spring-web. The following example shows how.
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))
}
// ...
}
For details on view technologies integrated with Spring WebFlux, see View Technologies.
1.11.8. Static Resources
This option provides a convenient way to serve static resources from a list of Resource-based locations.
In the following example, requests that start with /resources are handled by finding static resources relative to /static on the classpath by using the relative path. To make full use of browser caching and reduce HTTP requests made by the browser, resources are configured with a one-year cache lifetime. If a Last-Modified header is present, its value is evaluated and a 304 status code is returned.
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))
}
}
Resource handlers also support chains of ResourceResolver implementations and ResourceTransformer implementations. You can use them to create a toolchain for working with optimized resources.
You can use VersionResourceResolver for versioned resource URLs based on an MD5 hash computed from content, a fixed application version, or other information. ContentVersionStrategy, the MD5 hash strategy, is suitable with a few exceptions to watch for, such as JavaScript resources used by module loaders.
The following example shows how to use VersionResourceResolver in Java configuration.
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("/**"))
}
}
You can use ResourceUrlProvider to rewrite URLs and apply the full chain of resolvers and transformers, for example to insert a version. WebFlux configuration provides ResourceUrlProvider so it can be injected elsewhere.
Unlike Spring MVC, WebFlux currently has no way to transparently rewrite static resource URLs because there is no view technology that can use the non-blocking chain of resolvers and transformers. If you only serve local resources, a workaround is to use ResourceUrlProvider directly, for example through a custom element, and block.
When using both EncodedResourceResolver, for example Gzip or Brotli encoding, and VersionedResourceResolver, register them in this order so content-based versions are always calculated reliably from the unencoded file.
WebJars are also supported through WebJarsResourceResolver, which is automatically registered when the org.webjars:webjars-locator-core library is present on the classpath. The resolver can rewrite URLs that include the jar version and can also work with versionless incoming URLs, for example from /jquery/jquery.min.js to /jquery/1.2.0/jquery.min.js.
1.11.9. Path Matching
You can configure options for path matching. For details about individual options, see the PathMatchConfigurer javadoc. The following example shows how to use 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 uses a parsed representation of the request path called
RequestPathto access decoded path segment values and remove semicolon content, that is, path or matrix variables. In other words, unlike Spring MVC, you do not need to specify whether to decode the request path or remove semicolon content for path matching.Spring WebFlux also does not support suffix pattern matching, unlike Spring MVC, and it is recommended to move away from relying on it.
1.11.10. WebSocketService
WebFlux Java configuration declares a WebSocketHandlerAdapter bean that supports invoking WebSocket handlers. In other words, all that is required to handle WebSocket handshake requests is to map a WebSocketHandler to a URL through SimpleUrlHandlerMapping.
In some cases, you may need to provide a WebSocketService that can configure properties of the WebSocket server and create a WebSocketHandlerAdapter bean. For example:
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
@EnableWebFlux imports DelegatingWebFluxConfiguration:
- Provides default Spring settings for WebFlux applications.
- Detects
WebFluxConfigurerimplementations, delegates to them, and customizes the configuration.
For advanced configuration mode, remove @EnableWebFlux and extend DelegatingWebFluxConfiguration directly instead of implementing WebFluxConfigurer, as shown in the following example.
Java
@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {
// ...
}
Kotlin
@Configuration
class WebConfig : DelegatingWebFluxConfiguration {
// ...
}
You can keep existing methods in WebConfig, but you can also override bean declarations from the base class, and you can still have any number of other WebFluxConfigurer implementations on the classpath.