Spring WebFlux, как и Spring MVC, разработан по шаблону единой точки входа (front controller), где центральный WebHandler, DispatcherHandler, обеспечивает общий алгоритм обработки запросов, а фактическая работа выполняется конфигурируемыми компонентами-делегатами. Эта модель является гибкой и поддерживает различные рабочие процессы.

DispatcherHandler обнаруживает необходимые ему компоненты-делегаты из конфигурации Spring. Он также разработан таким образом, чтобы выступать в роли бина Spring, и реализует ApplicationContextAware для доступа к контексту, в котором он выполняется. Если DispatcherHandler объявлен с именем бина webHandler, то он, в свою очередь, обнаруживается WebHttpHandlerBuilder, который собирает цепочку обработки запросов.

Конфигурация Spring в приложении на WebFlux обычно содержит:

  • DispatcherHandler с именем бина webHandler;

  • Бины WebFilter и WebExceptionHandler;

  • Специальные бины DispatcherHandler;

  • И другое.

Конфигурация передается WebHttpHandlerBuilder для построения цепочки обработки, как показано в следующем примере:

Java
ApplicationContext context = ...
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context).build();
Kotlin
val context: ApplicationContext = ...
val handler = WebHttpHandlerBuilder.applicationContext(context).build()

Полученный HttpHandler готов к использованию с серверным адаптером.

1.3.1. Специализированные виды бинов

DispatcherHandler делегирует специальным бинам обработку запросов и выдачу соответствующих ответов. Под "специальными бинами" мы подразумеваем управляемые Spring экземпляры Object, которые реализуют контракты фреймворка WebFlux. Обычно они имеют встроенные контракты, но вы можете настроить их свойства, расширить их или заменить.

В следующей таблице перечислены специальные бины, обнаруживаемые DispatcherHandler. Обратите внимание, что существуют также некоторые другие типы бинов, определяемые на более низком уровне.

Тип бина Пояснение

HandlerMapping

Отображает запрос на обработчик. Отображение основывается на некоторых критериях, детали которых зависят от реализации HandlerMapping – аннотированные контроллеры, простые отображения по шаблону URL-адресов и др.

Основными реализациями HandlerMapping являются RequestMappingHandlerMapping для аннотированных с помощью @RequestMapping методов, RouterFunctionMapping для функциональных маршрутов конечных точек и SimpleUrlHandlerMapping для явной регистрации шаблонов путей URI-идентификаторов и экземпляров WebHandler.

HandlerAdapter

Помогает DispatcherHandler вызывать обработчик, отображенный на запрос, независимо от того, как этот обработчик будет вызван фактически. Например, вызов аннотированного контроллера требует разрешения аннотаций. Основная цель HandlerAdapter - оградить DispatcherHandler от таких деталей.

HandlerResultHandler

Обрабатывает результат вызова обработчика и завершает ответ.

Конфигурация WebFlux

Приложения могут объявлять бины инфраструктуры, которые необходимы для обработки запросов. Однако в большинстве случаев конфигурация WebFlux является лучшей отправной точкой. В ней объявляются необходимые бины и предоставляется API обратного вызова конфигурации более высокого уровня для настройки.

Spring Boot полагается на конфигурацию WebFlux для конфигурирования Spring WebFlux, а также предоставляет множество дополнительных удобных опций.

1.3.3. Обработка

DispatcherHandler обрабатывает запросы следующим образом:

  • Каждому HandlerMapping предлагается найти подходящий обработчик, и используется первое совпадение.

  • Если обработчик найден, он выполняется через соответствующий HandlerAdapter, который открывает возвращаемое значение после выполнения в виде HandlerResult.

  • HandlerResult передается соответствующему HandlerResultHandler для завершения обработки путем записи в ответ непосредственно или с помощью представления для визуализации.

1.3.4. Обработка результатов

Возвращаемое значение после вызова обработчика через HandlerAdapter оборачивается как HandlerResult, вместе с некоторым дополнительным контекстом, и передается первому HandlerResultHandler, который содержит утверждение о его поддержке. В следующей таблице показаны доступные реализации HandlerResultHandler, все они объявлены в конфигурации WebFlux:

Тип обработчика результатов Возвращаемые значения Порядок по умолчанию

ResponseEntityResultHandler

ResponseEntity, обычно из экземпляров аннотации @Controller.

0

ServerResponseResultHandler

ServerResponse, обычно от функциональных конечных точек.

0

ResponseBodyResultHandler

Обработка возвращаемых значений из методов, помеченных аннотацией @ResponseBody, или классов, помеченных аннотацией @RestController.

100

ViewResolutionResultHandler

CharSequence, View, Model, Map, Rendering или любой другой Object считается атрибутом модели.

Integer.MAX_VALUE

Исключения

HandlerResult, возвращаемый из HandlerAdapter, может открывать функцию для обработки ошибок на основе какого-либо механизма, специфичного для обработчика. Эта функция ошибки вызывается, если:

  • Вызов обработчика (например, аннотация @Controller) завершается ошибкой.

  • Обработка возвращаемого значения обработчика через HandlerResultHandler завершает ошибкой.

Функция ошибки может изменить ответ (например, на статус ошибки), при условии, что сигнал ошибки возникает до того, как реактивный тип, возвращаемый обработчиком, произведет какие-либо элементы данных.

Так поддерживаются методы, аннотированные @ExceptionHandler в классах, аннотированных @Controller. В противоположность этому их поддержка в Spring MVC построена на HandlerExceptionResolver. Обычно это не играет роли. Однако следует помнить, что в WebFlux нельзя использовать аннотацию @ControllerAdvice для обработки исключений, возникающих до выбора обработчика.

См. также подраздел "Управление исключениями " в разделе "Аннотированный контроллер" или подраздел "Исключения" в разделе, посвященном API WebHandler.

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

Распознавание представлений позволяет осуществлять визуализацию в браузере с помощью HTML-шаблона и модели, не привязывая вас к конкретной технологии представления. В Spring WebFlux распознавание представлений поддерживается специальным HandlerResultHandler, который использует экземпляры ViewResolver для отображения строки (представляющей логическое имя представления) на экземпляр View. Затем View используется для визуализации ответа.

Обработка

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

  • String, CharSequence: Логическое имя представления, которое должно быть разрешено в View через список сконфигурированных реализаций ViewResolver.

  • void: Выбирается имя представления по умолчанию на основе пути запроса, за вычетом ведущей и последующей косой черты, и разрешается в View. То же самое происходит, если не было указано имя представления (например, был возвращен атрибут модели) или есть асинхронное возвращаемое значение (например, Mono завершилось пустым).

  • Rendering: API для сценариев распознавания представлений. Изучите возможности вашей IDE с помощью автодополнения кода.

  • Model, Map: Дополнительные атрибуты модели, которые должны быть добавлены в модель для запроса.

  • Любое другое: Любое другое возвращаемое значение (кроме простых типов, определяемых BeanUtils#isSimpleProperty) считается атрибутом модели, который должен быть добавлен в модель. Имя атрибута выводится из имени класса с помощью соглашений, если отсутствует аннотация метода обработчика @ModelAttribute.

Модель может содержать асинхронные, реактивные типы (например, из Reactor или RxJava). Перед визуализацией представление AbstractView разрешает такие атрибуты модели в конкретные значения и обновляет модель. Однозначные реактивные типы разрешаются в одно значение или без значения (если пусто), а многозначные реактивные типы (например, Flux<T>) собираются и разрешаются в List<T>.

Конфигурирование распознавания представлений сводится просто к добавлению бина ViewResolutionResultHandler в конфигурацию Spring. Конфигурация WebFlux предусматривает выделенный API конфигурации для распознавания представлений.

Перенаправление

Специальный префикс redirect: в имени представления позволяет выполнить перенаправление. UrlBasedViewResolver (и подклассы) распознает это как указание на необходимость перенаправления. Остальная часть имени представления - это URL-адрес перенаправления.

Чистый результат такой же, как если бы контроллер возвращал RedirectView или Rendering.redirectTo("abc").build(), но теперь сам контроллер может оперировать логическими именами представлений. Имя представления, такое как redirect:/some/resource, относится к текущему приложению, в то время как имя представления, такое как redirect:https://example.com/arbitrary/path, перенаправляет на абсолютный URL-адрес.

Согласование содержимого

ViewResolutionResultHandler поддерживает согласование содержимого. Этот обработчик сравнивает типы среды передачи данных запроса с типами среды передачи данных, поддерживаемыми каждым выбранным View. Используется первый же View, который поддерживает запрошенный тип(ы) среды передачи данных.

Для поддержки таких типов среды передачи данных, как JSON и XML, Spring WebFlux предусматривает HttpMessageWriterView, которое является специальным View, осуществляющим визуализацию через HttpMessageWriter. Как правило, эти представления конфигурируются как представления по умолчанию через конфигурацию WebFlux. Представления по умолчанию всегда выбираются и используются, если соответствуют запрашиваемому типу среды передачи данных.