Einführung in Spring WebFlux
Spring WebFlux ist das neue Modul, das in Spring 5 eingeführt wurde. Spring WebFlux ist der erste Schritt in Richtung eines reaktiven Programmiermodells im Spring-Framework.
Reaktive Programmierung mit Spring
Wenn Sie neu in der reaktiven Programmierung sind, würde ich Ihnen dringend empfehlen, sich die folgenden Artikel durchzulesen, um mehr über die reaktive Programmierung zu erfahren.
Spring WebFlux
Spring WebFlux ist die Alternative zum Spring MVC-Modul. Spring WebFlux wird verwendet, um vollständig asynchrone und nicht-blockierende Anwendungen auf Basis des Event-Loop-Ausführungsmodells zu erstellen. Das untenstehende Diagramm aus der offiziellen Spring-Dokumentation bietet einen großartigen Einblick in den Vergleich von Spring WebFlux mit Spring Web MVC.spring webflux und spring mvcWenn Sie eine Webanwendung oder einen Rest-Webservice auf einem nicht-blockierenden, reaktiven Modell entwickeln möchten, können Sie sich Spring WebFlux ansehen. Spring WebFlux wird auf Tomcat, Jetty, Servlet 3.1+ Containern sowie auf Nicht-Servlet-Laufzeitumgebungen wie Netty und Undertow unterstützt. Spring WebFlux basiert auf Project Reactor. Project Reactor ist die Implementierung der Reactive Streams-Spezifikation. Reactor bietet zwei Typen:
- Mono: implementiert Publisher und gibt 0 oder 1 Elemente zurück
- Flux: implementiert Publisher und gibt N Elemente zurück.
Spring WebFlux Hallo Welt-Beispiel
Lassen Sie uns eine einfache Spring WebFlux Hallo Welt-Anwendung erstellen. Wir werden einen einfachen Rest-Webservice erstellen und Spring Boot verwenden, um ihn auf dem standardmäßigen Netty-Server auszuführen. Unsere endgültige Projektstruktur sieht wie im untenstehenden Bild aus.spring webflux beispielLassen Sie uns jede Komponente der Anwendung einzeln betrachten.
Maven-Abhängigkeiten
<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 Beispiel</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>
Die wichtigsten Abhängigkeiten sind spring-boot-starter-webflux und spring-boot-starter-parent. Einige andere Abhängigkeiten sind für das Erstellen von JUnit-Testfällen.
Spring WebFlux Handler
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 helloWorld(ServerRequest request) {
return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
.body(BodyInserters.fromObject("Hallo Welt!"));
}
}
Beachten Sie, dass die reaktive Komponente Mono den ServerResponse-Körper hält. Sehen Sie sich auch die Funktionskette an, um den Rückgabetyp, den Antwortcode und den Körper festzulegen.
Spring WebFlux Router
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 routeHelloWorld(HelloWorldHandler helloWorldHandler) {
return RouterFunctions.route(RequestPredicates.GET("/helloWorld")
.and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), helloWorldHandler::helloWorld);
}
}
Also wird eine GET-Methode für /helloWorld bereitgestellt, und der Clientaufruf sollte eine Antwort im Klartext akzeptieren.
Spring Boot-Anwendung
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);
}
}
Wenn Sie sich den obigen Code ansehen, gibt es nichts, was mit Spring WebFlux zu tun hat. Aber Spring Boot wird unsere Anwendung als Spring WebFlux konfigurieren, da wir die Abhängigkeit des spring-boot-starter-webflux-Moduls hinzugefügt haben.
Unterstützung von Java 9-Modulen
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;
}
Unsere Anwendung ist bereit, auf Java 8 ausgeführt zu werden, aber wenn Sie Java 9 verwenden, müssen wir auch die Klasse module-info.java hinzufügen.
Die Spring Boot-App ausführen
Wenn Sie Spring-Unterstützung in Eclipse haben, können Sie die obige Klasse als Spring Boot-App ausführen.Eclipse run as spring boot appWenn Sie die Befehlszeile verwenden möchten, öffnen Sie das Terminal und führen Sie den Befehl mvn spring-boot:run aus dem Projektquellverzeichnis aus. Sobald die App läuft, achten Sie auf die folgenden Protokollmeldungen, um sicherzustellen, dass alles in Ordnung ist mit unserer App. Das ist auch hilfreich, wenn Sie diese einfache App erweitern, indem Sie weitere Routen und Funktionalitäten hinzufügen.
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)
Spring WebFlux App Test
Wir können unsere App auf verschiedene Weisen testen.
- Mit CURL-Befehl
- URL im Browser starten
- Mit WebTestClient von Spring 5
- Mit WebClient von Spring Web Reactive
Zusammenfassung
In dieser Einführung haben wir über Spring WebFlux gelernt und wie man einen Hallo Welt reaktiven Restful-Webservice erstellt. Es ist gut zu sehen, dass beliebte Frameworks wie Spring die reaktive Programmierung unterstützen. Aber wir haben noch viel zu tun, denn wenn nicht alle Ihre Abhängigkeiten reaktiv und nicht-blockierend sind, dann ist Ihre Anwendung auch nicht wirklich reaktiv. Zum Beispiel haben relationale Datenbankanbieter keine reaktiven Treiber, weil sie von JDBC abhängen, das nicht reaktiv ist. Daher ist auch die Hibernate-API nicht reaktiv. Wenn Sie relationale Datenbanken verwenden, können Sie also noch keine wirklich reaktive Anwendung erstellen. Ich hoffe jedoch, dass sich das früher oder später ändern wird.