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应用程序运行即可,您应该看到带有许多调试消息的正确输出。

