Spring WebFlux – Spring Reactive编程

时间:2020-02-23 14:36:02  来源:igfitidea点击:

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