Поиск по сайту:

Spring WebFlux — Spring Reactive Programming


Spring WebFlux — это новый модуль, представленный в Spring 5. Spring WebFlux — это первый шаг к модели реактивного программирования в среде Spring.

Spring реактивное программирование

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

  • Реактивный манифест
  • Реактивные потоки
  • Реактивные потоки Java 9
  • RxJava

Если вы новичок в Spring 5, ознакомьтесь с возможностями Spring 5.

Весенний веб-флюкс

  1. Mono: реализует Publisher и возвращает 0 или 1 элемент
  2. Flux: реализует Publisher и возвращает N элементов.

Пример Spring WebFlux Hello World

Зависимости Spring WebFlux Maven

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.journaldev.spring</groupId>
  <artifactId>SpringWebflux</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>Spring WebFlux</name>
  <description>Spring WebFlux Example</description>
  
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <jdk.version>1.9</jdk.version>
    </properties>
    
  <parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.1.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</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>
	<repositories>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</pluginRepository>
		<pluginRepository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.7.0</version>
                    <configuration>
                        <source>${jdk.version}</source>
                        <target>${jdk.version}</target>
                    </configuration>
                </plugin>
            </plugins>
    </pluginManagement>
    </build>
    
</project>

Наиболее важными зависимостями являются spring-boot-starter-webflux и spring-boot-starter-parent. Некоторые другие зависимости предназначены для создания тестовых случаев JUnit.

Весенний обработчик WebFlux

Метод Spring WebFlux Handler обрабатывает запрос и возвращает Mono или Flux в качестве ответа.

package com.journaldev.spring.component;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;

@Component
public class HelloWorldHandler {

	public Mono<ServerResponse> helloWorld(ServerRequest request) {
		return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
			.body(BodyInserters.fromObject("Hello World!"));
	}
}

Обратите внимание, что реактивный компонент Mono содержит тело ServerResponse. Также посмотрите на цепочку функций, чтобы установить тип возвращаемого содержимого, код ответа и тело.

Весенний маршрутизатор WebFlux

Метод маршрутизатора используется для определения маршрутов для приложения. Эти методы возвращают объект RouterFunction, который также содержит тело ServerResponse.

package com.journaldev.spring.component;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

@Configuration
public class HelloWorldRouter {

	@Bean
	public RouterFunction<ServerResponse> routeHelloWorld(HelloWorldHandler helloWorldHandler) {

		return RouterFunctions.route(RequestPredicates.GET("/helloWorld")
                .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), helloWorldHandler::helloWorld);
	}
}

Итак, мы предоставляем метод GET для /helloWorld, и клиентский вызов должен принимать простой текстовый ответ.

Весеннее загрузочное приложение

Давайте настроим наше простое приложение WebFlux с помощью Spring Boot.

package com.journaldev.spring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

Если вы посмотрите на приведенный выше код, там нет ничего, связанного с Spring WebFlux. Но Spring Boot настроит наше приложение как Spring WebFlux, поскольку мы добавили зависимость от модуля spring-boot-starter-webflux.

Поддержка модулей Java 9

Наше приложение готово к выполнению на Java 8, но если вы используете Java 9, нам также необходимо добавить класс module-info.java.

module com.journaldev.spring {
    requires reactor.core;
    requires spring.web;
    requires spring.beans;
    requires spring.context;
    requires spring.webflux;
    requires spring.boot;
    requires spring.boot.autoconfigure;
    exports com.journaldev.spring;
}

Запуск приложения Spring WebFlux Spring Boot

2018-05-07 15:01:47.893  INFO 25158 --- [           main] o.s.w.r.f.s.s.RouterFunctionMapping      : Mapped ((GET && /helloWorld) && Accept: [text/plain]) -> com.journaldev.spring.component.HelloWorldRouter$$Lambda$501/704766954@6eeb5d56
2018-05-07 15:01:48.495  INFO 25158 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext     : Started HttpServer on /0:0:0:0:0:0:0:0:8080
2018-05-07 15:01:48.495  INFO 25158 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2018-05-07 15:01:48.501  INFO 25158 --- [           main] com.journaldev.spring.Application        : Started Application in 1.86 seconds (JVM running for 5.542)

Из логов видно, что наше приложение работает на сервере Netty на порту 8080. Давайте продолжим и протестируем наше приложение.

Весенний тест приложения WebFlux

Мы можем протестировать наше приложение различными методами.

Резюме

В этом посте мы узнали о Spring WebFlux и о том, как создать реактивный веб-сервис Hello World Restful. Приятно видеть, что популярные фреймворки, такие как Spring, поддерживают модель реактивного программирования. Но нам нужно охватить многое, потому что, если все ваши зависимости не являются реактивными и неблокирующими, ваше приложение также не является по-настоящему реактивным. Например, поставщики реляционных баз данных не имеют реактивных драйверов, потому что они зависят от JDBC, который не является реактивным. Следовательно, Hibernate API также не является реактивным. Поэтому, если вы используете реляционные базы данных, вы пока не можете создать действительно реактивное приложение. Я надеюсь, что это изменится раньше, чем позже.

Вы можете скачать код проекта из моего репозитория GitHub.

Ссылка: Официальная документация