Actual Spring Boot 2.0 Reactive Programming Series — первый опыт WebFlux

Spring Boot задняя часть Spring контейнер

предисловие

Представлено вышемодель реактивного программированиясвязанные понятия, даSpring ReactorОсновнойAPIПодведен краткий итог. Эта статья будетSpring 5 WebFluxделать соответствующие презентации, в том числе знакомитьServlet 3.1 +, каждый функциональный компонентRouter Functions,WebFluxиReactive Streamsд., и какSpring Boot 2.0соответственно вГлобальная маршрутизация объектовиMVC контроллерспособ настройкиHTTPобработка запросов.

текст

Введение в Spring 5 WebFlux

оSpring 5изWebFluxРеактивное программирование, картинка ниже — традиционноеSpring Web MVCструктура иSpring 5Недавно добавлено на основеReactive StreamsизSpring WebFluxРамка. можно использоватьwebFluxмодули для сборкиАсинхронный,неблокирующий,управляемый событиямиуслуги, которыеМасштабируемостьВыступил очень хорошо.

как показано на рисунке,WebFluxМодули сверху внизRouter Functions,WebFlux,Reactive StreamsТри новых компонента.

Введение в API сервлетов 3.1+

WebFluxМодуль должен работать в реализацииServlet 3.1+ Спецификацияна контейнере.Servlet 3.1Добавлено в спецификациюАсинхронная обработкаподдержка в новомServletв спецификации,ServletТемы не должны бытьблокировка ожиданиядо завершения бизнес-процесса.

существуетServlet 3.1, потоковая модель обработки его запросов примерно такова:

  1. ServletПосле того, как поток получает новый запрос, ему не нужно ждать завершения бизнес-обработки перед выводом результата, а он делегирует запрос другому потоку (бизнес-потоку) для завершения.

  2. ServletПоток вернется в контейнер после завершения делегирования для получения новых запросов.

Servlet 3.1Эта норма особенно применима кБизнес-обработка занимает много временипо сценарию может снизитьресурсы серверазаполняемость и увеличениеПараллельная скорость обработки, и для тех, кто можетБыстрый ответПольза от сцены невелика.

такWebFluxПоддерживаемые контейнерыTomcat,JettyЖдатьКонтейнер синхронизации,так же может бытьNettyиUndertowэтот видАсинхронный контейнер. в контейнереSpring WebFluxбудетвходной потокадаптирован кMonoилиFluxФормат унифицирован.

Функциональные модули для Spring WebFlux

Ниже описано изображение вышеWebFluxКаждый модуль:

1. Router Functions

по стандарту@Controller,@RequestMappingожидающийSpring MVCАннотация, предоставляющая наборфункциональный стильизAPI, создаватьRouter,HandlerиFilter.

2. WebFlux

Основные компоненты, координирующие предоставление вышестоящих и нижестоящих компонентовреактивное программированиеслужба поддержки.

3. Reactive Streams

поддержкаобратное давление (Backpressure)изСтандарт обработки асинхронных потоков данных, основная реализация имеетRxJavaиReactor,Spring WebFluxинтегрированныйReactor.

Flux

FluxиMonoпринадлежатьиздатель событий, похожий нарежиссер, потребителямПредоставить интерфейс подписки. Когда происходит событие,FluxилиMonoперезвонитпотребительсоответствующий способ уведомленияпотребительсоответствующее событие.

На картинке нижеFluxСхема рабочего процесса:

оFluxрабочий режим, видно чтоFluxможет вызвать(emit)полноitem, и этиitemможет пройти несколькоOperatorsа потом былsubscribe, используется следующееFluxПример:

Flux.fromIterable(getSomeLongList())
    .mergeWith(Flux.interval(100))
    .doOnNext(serviceA::someObserver)
    .map(d -> d * 2)
    .take(3)
    .onErrorResumeWith(errorHandler::fallback)
    .doAfterTerminate(serviceM::incrementTerminate)
    .subscribe(System.out::println);

Mono

На картинке нижеMonoПроцесс обработки можно увидеть интуитивноMonoиFluxРазница:

Monoтолько триггер(emit)Одинitem, используется следующееMonoПример:

Mono.fromCallable(System::currentTimeMillis)
    .flatMap(time -> Mono.first(serviceA.findRecent(time), serviceB.findRecent(time)))
    .timeout(Duration.ofSeconds(3), errorHandler::fallback)
    .doOnSuccess(r -> serviceM.incrementSuccess())
    .subscribe(System.out::println);

Spring Boot 2.0 Reactive Stack

Spring Boot Webfluxоснован наReactorосуществленный.Spring Boot 2.0в том числе новыйspring-webfluxмодуль. Этот модуль содержитОтзывчивый HTTPиWebSocketподдержка клиентов, а такжеREST,HTMLиWebSocket интерактивные программыслужба поддержки. Вообще говоря,Spring MVCиспользуется дляСинхронная обработка,Spring Webfluxиспользуется дляАсинхронная обработка.

Как показано выше, изWebОт уровня представления к доступу к данным, к контейнеру,Spring Boot 2.0также обеспечиваетсинхронная блокировкаиАсинхронный неблокирующийдва полных комплектаAPI Stack.

Сравните различия между ними сверху вниз:

API Stack Sevlet Stack Reactive Stack
Уровень веб-контроля Spring MVC Spring WebFlux
уровень аутентификации безопасности Spring Security Spring Security
уровень доступа к данным Spring Data Repositories Spring Data Reactive Repositories
API-интерфейс контейнера Servlet API Reactive Streams Adapters
встроенный контейнер Servlet Containers Netty, Servlet 3.1+ Containers

Применимая сцена

Когда используется контрольный слойSpring WebFlux, необходимо использовать уровень аутентификации безопасности и уровень доступа к данным ниже него.Reactive API. Второй,Spring Data Reactive RepositoriesВ настоящее время поддерживается толькоMongoDB,RedisиCouchbaseНесколько других типов, которые не поддерживают управление транзакциямиNOSQL. Эти недостатки и риски необходимо взвешивать при выборе технологий, таких как:

  1. Spring MVCЕсли он соответствует сцене, вам не нужно менять его наSpring WebFlux.

  2. Чтобы обратить внимание на поддержку контейнера, вы можете посмотреть на нижний слойвстроенный контейнерслужба поддержки.

  3. МикросервисыАрхитектура,Spring WebFluxиSpring MVCМожно смешать. особенно развитыйIO интенсивныйПри подаче можно выбратьSpring WebFluxдостигать.

модель программирования

Spring 5 Webмодуль содержитSpring WebFluxизHTTPАннотация. похожийServlet API,WebFluxпри условииWebHandler APIопределятьнеблокирующий APIабстрактный интерфейс. Вы можете выбрать одну из следующих двух реализаций модели программирования:

  1. Слой управления аннотациями:иMVCбыть последовательным,WebFluxтакже поддерживаетОтветная реакция @RequestBodyаннотация.

  2. Функциональные конечные точки:на основеlambdaОблегченная модель программирования длясоздать маршрутиобработать запросИнструмент. Самое большое отличие от вышеперечисленных заключается в том, что эта модель,весь процессконтрольответ на запросжизненный процесс

встроенный контейнер

иSpring BootЗапустите приложение как большую рамку, ноSpring WebFluxПо умолчаниюNettyзапускается и автоматически устанавливаетсяпорт по умолчаниюза8080. Также предоставляетJetty,Undertowи т.п. поддержка контейнера. Разработчик сам добавляет соответствующий контейнерStarterЗависимости компонентов можно настроить и использовать соответствующиеЭкземпляр встроенного контейнера.

Примечание: Должен быть контейнер Servlet 3.1+, такой как Tomcat, Jetty, или не-Servlet контейнер, такой как Netty и Undertow.

Стартовый компонент

иSpring Bootкак большая рамка,Spring Boot Webfluxобеспечивает многоиз коробкиизStarterкомпоненты. Добавить кspring-boot-starter-webfluxзависимости, его можно использовать для построенияОтзывчивый APIуслуги, которые включаютWebFluxиTomcat встроенный контейнерЖдать.

быстрый старт

Скелет проекта сборки Spring Initializr

использоватьSpring InitializerГенерировать быстроSpring BootПримените, настройте информацию о проекте и установите зависимости.

Настройка зависимостей Maven

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Класс запуска Spring Boot

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

Настроить класс сущности

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Message {
    String body;
}

1. Метод контроллера MVC

1.1 Написание контроллера

@RestController
@RequestMapping
public class MessageController {
    @GetMapping
    public Flux<Message> allMessages(){
        return Flux.just(
            Message.builder().body("hello Spring 5").build(),
            Message.builder().body("hello Spring Boot 2").build()
        );
    }  
}

1.2 Написание тестовых классов

@RunWith(SpringRunner.class)
@WebFluxTest(controllers = MessageController.class)
public class DemoApplicationTests {
    @Autowired
    WebTestClient client;

    @Test
    public void getAllMessagesShouldBeOk() {
        client.get().uri("/").exchange().expectStatus().isOk();
    }
}

1.3. Просмотр журнала запуска

2018-05-27 17:37:23.550  INFO 67749 --- [           main] s.w.r.r.m.a.RequestMappingHandlerMapping : Mapped "{[],methods=[GET]}" onto reactor.core.publisher.Flux<com.example.demo.Message> com.example.demo.MessageController.allMessages()
2018-05-27 17:37:23.998  INFO 67749 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext     : Started HttpServer on /0:0:0:0:0:0:0:0:8080
2018-05-27 17:37:23.999  INFO 67749 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2018-05-27 17:37:24.003  INFO 67749 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.6 seconds (JVM running for 2.274)

Из лога видно, что:

  1. при запускеWebFluxиспользоватьMVCоригинальныйRequestMappingHandlerMappingв контроллерепуть запросаиMVCсерединапроцессорсвязывать.
  2. Spring WebFluxПо умолчаниюNettyв видевстроенный контейнер, а порт запуска по умолчанию8080.

доступhttp://localhost:8080, возвращенный результат выглядит следующим образом:

2. Глобальный метод API маршрутизатора

2.1 Настройка глобального маршрутизатора Bean

@Configuration
public class DemoRouterConfig {
    @Bean
    public RouterFunction<ServerResponse> routes() {
        return route(GET("/"), (ServerRequest req)-> ok()
                .body(
                    BodyInserters.fromObject(
                        Arrays.asList(
                            Message.builder().body("hello Spring 5").build(),
                            Message.builder().body("hello Spring Boot 2").build()
                        )
                    )
                )
        );
    }
}

2.2 Написание тестовых классов

@RunWith(SpringRunner.class)
@WebFluxTest
public class DemoApplicationTests {    
    @Autowired
    WebTestClient client;
    
    @Test
    public void getAllMessagesShouldBeOk() {
        client.get().uri("/").exchange().expectStatus().isOk();
    }
}

2.3 Просмотр журнала запуска

бегатьSpring BootЗапустите класс записи, журнал запуска выглядит следующим образом (неважное опущено):

2018-05-27 17:20:28.870  INFO 67696 --- [           main] o.s.w.r.f.s.s.RouterFunctionMapping      : Mapped (GET && /) -> com.example.demo.DemoRouterConfig$$Lambda$213/1561745898@3381b4fc
2018-05-27 17:20:28.931  INFO 67696 --- [           main] o.s.w.r.r.m.a.ControllerMethodResolver   : Looking for @ControllerAdvice: org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext@1460a8c0: startup date [Sun May 27 17:20:27 CST 2018]; root of context hierarchy
2018-05-27 17:20:29.311  INFO 67696 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext     : Started HttpServer on /0:0:0:0:0:0:0:0:8080
2018-05-27 17:20:29.312  INFO 67696 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2018-05-27 17:20:29.316  INFO 67696 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 2.137 seconds (JVM running for 3.169)

Как видно из лога: при запускеWebFluxиспользоватьRouterFunctionMappingбудетRouterFunctionвнутреннийглобальный путьиобработка запросаОтображение и привязка сделаны.

доступhttp://localhost:8080, возвращенный результат выглядит следующим образом:

Видно, что либо с помощьюFucntional Routerвсе ещеMVC Controller, может произвести тот же эффект!

Среда выполнения разработки

  • JDK 1.8 + : Spring Boot 2.xТребоватьJDK 1.8среды и выше. Кроме того,Spring Boot 2.xтолько совместимыеSpring Framework 5.0и выше.

  • Maven 3.2 +: заSpring Boot 2.xПредоставляются соответствующие инструменты построения зависимостей.Maven, нужная версия3.2и выше. использоватьGradleтогда нужно1.12и выше.MavenиGradleКаждый может выбрать то, что ему нравится.

резюме

Эта статья впервыеSpring 5 WebFluxпредставлены отдельно, включая введениеServlet 3.1 +, каждый функциональный компонентRouter Functions,WebFluxиReactive StreamsЖдать. затем вSpring Boot 2.0подробно описаноReactive StackиServlet StackКомпозиционная разница , и даны соответственноWebFluxна основеГлобальная маршрутизация объектовиконтроллерконфигурация и варианты использования.


Добро пожаловать в технический публичный аккаунт: Zero One Technology Stack

零壹技术栈

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