Java-конфігурація WebFlux оголошує компоненти, необхідні для обробки запитів з використанням анотованих контролерів або функціональних кінцевих точок, і передбачає API для налаштування конфігурації. Це означає, що тобі не потрібно розбиратися в базових бінах, що створюються Java-конфігурацією.

Якщо необхідні розширені налаштування, недоступні в конфігураційному API, ти можеш отримати повний контроль над конфігурацією за допомогою режиму розширеної конфігурації.

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

Ти можеш використовувати анотацію @EnableWebFlux у Java-конфігурації, як показано в наступному прикладі:

Java
@Configuration
@EnableWebFlux
public class WebConfig {
}
Kotlin
@Configuration
@EnableWebFlux
class WebConfig/span>

У попередньому прикладі низка інфраструктурних бінів 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.