Java-конфигурация WebFlux объявляет компоненты, необходимые для обработки запросов с использованием аннотированных контроллеров или функциональных конечных точек, и предусматривает API для настройки конфигурации. Это означает, что вам не потребуется разбираться в базовых бинах, создаваемых Java-конфигурацией.

Если необходимы расширенные настройки, недоступные в конфигурационном API, вы можете получить полный контроль над конфигурацией с помощью режима расширенной конфигурации.

Активация конфигурации WebFlux

Вы можете использовать аннотацию @EnableWebFlux в Java-конфигурации, как показано в следующем примере:

Java
@Configuration
@EnableWebFlux
public class WebConfig {
}
Kotlin
@Configuration
@EnableWebFlux
class WebConfig

В предыдущем примере ряд инфраструктурных бинов Spring WebFlux регистрируется и адаптируется к зависимостям, доступным в classpath – для JSON, XML и других форматов.

API конфигурации WebFlux

В своей Java-конфигурации вы можете реализовать интерфейс WebFluxConfigurer, как показано в следующем примере:

Java
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
// Реализовываем методы конфигурации...
}
Kotlin
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
// Реализовываем методы конфигурации...
}

Преобразование, форматирование

По умолчанию установлены форматтеры для различных типов чисел и дат наряду со средствами поддержки настройки через @NumberFormat и @DateTimeFormat для полей.

Чтобы зарегистрировать кастомные форматтеры и преобразователи в конфигурации Java, используйте следующее:

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 учитывает региональные настройки запроса при парсинге и форматировании значений даты. Это справедливо для форм, где даты представлены в виде строк с полями формы "input". Однако для полей формы "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)
}
}

Валидация

По умолчанию, если в classpath присутствует Bean Validation (например, Hibernate Validator), LocalValidatorFactoryBean регистрируется как глобальный валидатор для использования с аннотацией @Valid и свойства Validated на аргументах методов.

В 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 был куда-то внедрён, создайте бин и пометьте его аннотацией @Primary, чтобы избежать конфликта с тем, что был объявлен в конфигурации 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) {
// ...
}
}

Кодеки сообщений, передаваемых по протоколу HTTP

В следующем примере показано, как настроить чтение и запись тела запроса и ответа:

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 предусматривает набор читателей и писателей по умолчанию. Можно использовать его для добавления дополнительных читателей и писателей, настройки стандартных или полной замены стандартных.

Для Jackson JSON и XML рассмотрите возможность использования Jackson2ObjectMapperBuilder, который настраивает свойства библиотеки Jackson по умолчанию на следующие:

Также автоматически регистрируются следующие известные модули, если они обнаружены в classpath:

Распознаватели представлений

В следующем примере показано, как настроить распознавание представлений:

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();
}
// Конфигурируем 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()
}
// Конфигурируем 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
}
}

Для обеспечения поддержки согласования содержимого и визуализации других форматов через разрешение представления (помимо HTML), можно сконфигурировать одно или несколько представлений по умолчанию на основе реализации HttpMessageWriterView, которая принимает любой из доступных кодеков из spring-web. В следующем примере показано, как это сделать:

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))
}
// ...
}

Статические ресурсы

Эта опция обеспечивает удобный способ обработки статических ресурсов из списка местоположений на основе Resource.

В следующем примере, если запрос начинается с /resources, относительный путь используется для поиска и обработки статических ресурсов относительно /static в classpath. Ресурсы обрабатываются с истечением срока действия в один год, чтобы обеспечить максимальное использование кэша браузера и сократить количество HTTP-запросов, выполняемых браузером. Также вычисляется заголовок 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, которые могут быть использованы, чтобы создать набор инструментальных средств для работы с оптимизированными ресурсами.

Вы можете использовать VersionResourceResolver для версионированных URL-адресов ресурсов на основе хэша MD5, полученного из содержимого, неизменяемой версии приложения или другой информации. ContentVersionStrategy (хэш MD5) является продуманным выбором, но с некоторыми заметными исключениями (например, ресурсы JavaScript, используемые с загрузчиком модулей).

В следующем примере показано, как использовать VersionResourceResolver в конфигурации Java:

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 также поддерживаются при помощи WebJarsResourceResolver, который автоматически регистрируется при наличии библиотеки org.webjars:webjars-locator-core в classpath. Распознаватель может переписывать URL-адреса, чтобы включить в состав версию jar, а также сопоставлять входящие URL-адреса без версий - например, из /jquery/jquery.min.js в /jquery/1.2.0/jquery.min.js.

Java-конфигурация на основе ResourceHandlerRegistry предусматривает дополнительные возможности для тонкого контроля, например, логику работы при последнем изменении и оптимизированное разрешение ресурсов.

Сопоставление путей

Вы можете настроить параметры, связанные с сопоставлением путей. Подробнее об отдельных параметрах см. в javadoc по PathMatchConfigurer. В следующем примере показано, как использовать 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, где мы тоже рекомендуем отказаться от его использования.

WebSocketService

В Java-конфигурации WebFlux объявляется бин WebSocketHandlerAdapter, который обеспечивает поддержку вызова обработчиков WebSocket. Это означает, что для обработки запроса на подтверждение установления связи по протоколу WebSocket остается лишь сопоставить WebSocketHandler с URL-адресом через SimpleUrlHandlerMapping.

В некоторых случаях может потребоваться создать бин WebSocketHandlerAdapter с предусмотренной службой WebSocketService, которая позволяет настраивать свойства сервера, работающего с протоколом WebSocket. Например:

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)
}
}

Режим расширенной конфигурации

@EnableWebFlux импортирует DelegatingWebFluxConfiguration, который:

  • Передает конфигурацию Spring по умолчанию для приложений WebFlux

  • обнаруживает и делегирует полномочия реализации WebFluxConfigurer для настройки этой конфигурации.

В расширенном режиме вы можете удалить аннотацию @EnableWebFlux и производить расширение непосредственно из DelegatingWebFluxConfiguration вместо того, чтобы реализовывать WebFluxConfigurer, как показано в следующем примере:

Java
@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {
// ...
}
Kotlin
@Configuration
class WebConfig : DelegatingWebFluxConfiguration {
// ...
}

Можно сохранять существующие методы в WebConfig, но теперь также будет возможность переопределять объявления бинов из базового класса, и при этом все еще можно иметь любое количество других реализаций WebMvcConfigurer в classpath.

HTTP/2

HTTP/2 поддерживается в Reactor Netty, Tomcat, Jetty и Undertow. Однако есть некоторые предостережения, связанные с серверной конфигурацией. Более подробную информацию можно найти на вики-странице по HTTP/2.