Spring WebFlux – Spring Reactive编程
Spring WebFlux是Spring 5中引入的新模块。
SpringWebFlux是向Spring框架中的反应式编程模型迈出的第一步。
SpringWebFlux
Spring WebFlux是Spring MVC模块的替代方案。
Spring WebFlux用于创建基于事件循环执行模型的完全异步且非阻塞的应用程序。
Spring官方文档中的下图提供了关于Spring WebFlux与Spring Web MVC比较的深刻见解。
如果您希望在非阻塞反应模型上开发Web应用程序或者Rest Web服务,则可以研究Spring WebFlux。
Tomcat,Jetty,Servlet 3.1+容器以及非Servlet运行时(例如Netty和Undertow)都支持Spring WebFlux。
Spring WebFlux基于Project Reactor构建。
Project Reactor是Reactive Streams规范的实现。
Reactor提供两种类型:
- Mono:实现Publisher,并返回0或者1个元素
- Flux:实现Publisher,并返回N个元素。
Spring WebFlux Hello World示例
让我们构建一个简单的Spring WebFlux Hello World应用程序。
我们将创建一个简单的rest Web服务,并使用Spring Boot在默认的Netty服务器上运行它。
让我们逐一研究应用程序的每个组件。
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.theitroad.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测试用例的。
Spring WebFlux处理程序
Spring WebFlux Handler方法处理请求并返回Mono
或者Flux
作为响应。
package com.theitroad.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主体。
还要查看功能链,以设置返回内容类型,响应代码和主体。
Spring WebFlux路由器
路由器方法用于定义应用程序的路由。
这些方法返回同样包含ServerResponse主体的RouterFunction对象。
package com.theitroad.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); } }
因此,我们将为/helloWorld公开GET方法,并且客户端调用应接受纯文本响应。
Spring Boot应用程序
让我们使用Spring Boot配置我们的简单WebFlux应用程序。
package com.theitroad.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.theitroad.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.theitroad.spring; }
运行Spring WebFlux Spring Boot App
如果您在Eclipse中具有Spring支持,那么可以在类之上运行Spring Boot App。
如果您想使用命令行,请打开终端并从项目源目录运行命令" mvn spring-boot:run"。
应用程序运行后,请注意以下日志消息,以确保我们的应用程序一切正常。
当您通过添加更多路线和功能来扩展此简单应用程序时,这也很有帮助。
2016-05-07 15:01:47.893 INFO 25158 --- [ main] o.s.w.r.f.s.s.RouterFunctionMapping : Mapped ((GET && /helloWorld) && Accept: ) -> com.theitroad.spring.component.HelloWorldRouter$$Lambda1/704766954@6eeb5d56 2016-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 2016-05-07 15:01:48.495 INFO 25158 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080 2016-05-07 15:01:48.501 INFO 25158 --- [ main] com.theitroad.spring.Application : Started Application in 1.86 seconds (JVM running for 5.542)
从日志中可以清楚地看到我们的应用程序正在端口8080的Netty服务器上运行。
让我们继续测试我们的应用程序。
SpringWebFlux App测试
我们可以通过多种方法测试我们的应用。
- 使用CURL命令
- 在浏览器中启动URL
- 使用Spring 5中的WebTestClient这里是一个JUnit测试程序,用于使用Spring 5反应性Web中的WebTestClient测试我们的Rest Web服务。
运行它一个JUnit测试用例,它应该以飞快的速度通过。
- 从Spring Web Reactive使用WebClient我们还可以使用
WebClient
来调用REST Web服务。
只需将其作为一个简单的Java应用程序运行即可,您应该看到带有许多调试消息的正确输出。