Java-конфигурация WebFlux объявляет компоненты, необходимые для обработки запросов с использованием аннотированных контроллеров или функциональных конечных точек, и предусматривает API для настройки конфигурации. Это означает, что вам не потребуется разбираться в базовых бинах, создаваемых Java-конфигурацией.
Если необходимы расширенные настройки, недоступные в конфигурационном API, вы можете получить полный контроль над конфигурацией с помощью режима расширенной конфигурации.
Активация конфигурации WebFlux
Вы можете использовать аннотацию @EnableWebFlux
в Java-конфигурации, как показано в следующем примере:
@Configuration
@EnableWebFlux
public class WebConfig {
}
@Configuration
@EnableWebFlux
class WebConfig
В предыдущем примере ряд инфраструктурных бинов Spring WebFlux регистрируется и адаптируется к зависимостям, доступным в classpath – для JSON, XML и других форматов.
API конфигурации WebFlux
В своей Java-конфигурации вы можете реализовать интерфейс WebFluxConfigurer
, как показано в следующем примере:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
// Реализовываем методы конфигурации...
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
// Реализовываем методы конфигурации...
}
Преобразование, форматирование
По умолчанию установлены форматтеры для различных типов чисел и дат наряду со средствами поддержки настройки через @NumberFormat
и @DateTimeFormat
для полей.
Чтобы зарегистрировать кастомные форматтеры и преобразователи в конфигурации Java, используйте следующее:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun addFormatters(registry: FormatterRegistry) {
// ...
}
}
По умолчанию Spring WebFlux учитывает региональные настройки запроса при парсинге и форматировании значений даты. Это справедливо для форм, где даты представлены в виде строк с полями формы "input". Однако для полей формы "date" и "time" браузеры используют фиксированный формат, определенный в спецификации HTML. Для таких случаев форматирование даты и времени можно настроить следующим образом:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
@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
, как показано в следующем примере:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public Validator getValidator() {
// ...
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun getValidator(): Validator {
// ...
}
}
Обратите внимание, что также можно регистрировать реализации Validator
локально, как показано в следующем примере:
@Controller
public class MyController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new FooValidator());
}
}
@Controller
class MyController {
@InitBinder
protected fun initBinder(binder: WebDataBinder) {
binder.addValidators(FooValidator())
}
}
LocalValidatorFactoryBean
был куда-то внедрён, создайте бин и пометьте его аннотацией @Primary
, чтобы избежать конфликта с тем, что был объявлен в конфигурации MVC.Распознаватели типов содержимого
Вы можете конфигурировать то, каким образом Spring WebFlux определяет запрашиваемые типы сред передачи данных для экземпляров @Controller
из запроса. По умолчанию проверяемый только заголовок Accept
, но вы также можете активировать стратегию на основе параметров запроса.
В следующем примере показано, как настроить разрешение запрашиваемого типа содержимого:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
// ...
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun configureContentTypeResolver(builder: RequestedContentTypeResolverBuilder) {
// ...
}
}
Кодеки сообщений, передаваемых по протоколу HTTP
В следующем примере показано, как настроить чтение и запись тела запроса и ответа:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().maxInMemorySize(512 * 1024);
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
// ...
}
}
ServerCodecConfigurer
предусматривает набор читателей и писателей по умолчанию. Можно использовать его для добавления дополнительных читателей и писателей, настройки стандартных или полной замены стандартных.
Для Jackson JSON и XML рассмотрите возможность использования Jackson2ObjectMapperBuilder
, который настраивает свойства библиотеки Jackson по умолчанию на следующие:
-
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
– отключено. -
MapperFeature.DEFAULT_VIEW_INCLUSION
– отключено.
Также автоматически регистрируются следующие известные модули, если они обнаружены в classpath:
-
jackson-datatype-joda
: Поддержка типов Joda-Time. -
jackson-datatype-jsr310
: Поддержка типов API даты и времени Java 8. -
jackson-datatype-jdk8
: Поддержка других типов Java 8, таких какOptional
. -
jackson-module-kotlin
: Поддержка классов и классов данных Kotlin.
Распознаватели представлений
В следующем примере показано, как настроить распознавание представлений:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
// ...
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
// ...
}
}
ViewResolverRegistry
содержит сокращения для технологий представления, с которыми интегрируется Spring Framework. В следующем примере используется FreeMarker (что также требует настройки лежащей в основе технологии представления FreeMarker):
@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;
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.freeMarker()
}
// Конфигурируем FreeMarker...
@Bean
fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
setTemplateLoaderPath("classpath:/templates")
}
}
Также можно подключить любую реализацию ViewResolver
, как это показано в следующем примере:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
ViewResolver resolver = ... ;
registry.viewResolver(resolver);
}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
val resolver: ViewResolver = ...
registry.viewResolver(resolver
}
}
Для обеспечения поддержки согласования содержимого и визуализации других форматов через разрешение представления (помимо HTML), можно сконфигурировать одно или несколько представлений по умолчанию на основе реализации HttpMessageWriterView
, которая принимает любой из доступных кодеков из spring-web
. В следующем примере показано, как это сделать:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.freeMarker();
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
registry.defaultViews(new HttpMessageWriterView(encoder));
}
// ...
}
@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
. В следующем листинге показан пример:
@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));
}
}
@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:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public/")
.resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}
}
@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
.
ResourceHandlerRegistry
предусматривает дополнительные возможности для тонкого контроля, например, логику работы при последнем изменении и оптимизированное разрешение ресурсов.Сопоставление путей
Вы можете настроить параметры, связанные с сопоставлением путей. Подробнее об отдельных параметрах см. в javadoc по PathMatchConfigurer
. В следующем примере показано, как использовать PathMatchConfigurer
:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer
.setUseCaseSensitiveMatch(true)
.setUseTrailingSlashMatch(false)
.addPathPrefix("/api",
HandlerTypePredicate.forAnnotation(RestController.class));
}
}
@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. Например:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public WebSocketService getWebSocketService() {
TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
strategy.setMaxSessionIdleTimeout(0L);
return new HandshakeWebSocketService(strategy);
}
}
@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
, как показано в следующем примере:
@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {
// ...
}
@Configuration
class WebConfig : DelegatingWebFluxConfiguration {
// ...
}
Можно сохранять существующие методы в WebConfig
, но теперь также будет возможность переопределять объявления бинов из базового класса, и при этом все еще можно иметь любое количество других реализаций WebMvcConfigurer
в classpath.
HTTP/2
HTTP/2 поддерживается в Reactor Netty, Tomcat, Jetty и Undertow. Однако есть некоторые предостережения, связанные с серверной конфигурацией. Более подробную информацию можно найти на вики-странице по HTTP/2.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ