Spring Webflux 构建响应式 Restful Web 服务

Posted carl-zhao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Webflux 构建响应式 Restful Web 服务相关的知识,希望对你有一定的参考价值。

本指南将引导您完成创建“Hello, Spring!”使用Spring WebFlux的rest式web服务(Spring Boot 2.0的新版本),然后使用WebClient使用该服务(Spring Boot 2.0的新版本)。

1、你将建立什么

您将使用 Spring Webflux 和该服务的 WebClient 使用者构建一个RESTful web 服务。您将能够在两个系统中看到输出。和:

http://localhost:8080/hello

2、你需要什么

  • 大约15分钟
  • 最喜欢的文本编辑器或IDE
  • JDK 1.8及以上版本
  • Gradle 4+或Maven 3.2+
  • 你也可以将代码直接导入到你的IDE中:
    • Spring Tool Suite (STS)
    • IntelliJ IDEA

3、如何完成本指南

与大多数 Spring Getting Started 指南一样,您可以从头开始并完成每个步骤,也可以跳过您已经熟悉的基本设置步骤。无论哪种方式,您最终都会得到可工作的代码。

要从头开始,请转到“ 从 Spring Initializr 开始”。

要跳过这些基本步骤,请执行以下步骤:

当您完成时,您可以检查您的结果与代码 gs-reactive-rest-service/complete .

4、从 Spring Initializr 开始

您可以使用这个 预先初始化的项目 并单击 Generate 下载ZIP文件。该项目被配置为适合本教程中的示例。

手动初始化项目:

  • 导航到 https://start.spring.io。这个服务会拉入应用程序所需的所有依赖项,并为你完成大部分设置工作。
  • 选择 Gradle 或 Maven 和你想要使用的语言。本指南假设您选择了Java。
  • 单击 Dependencies 并选择 Spring Reactive Web
  • 点击 Generate
  • 下载得到的ZIP文件,它是用您的选择配置的web应用程序的存档文件。

5、创建 WebFlux Handler

我们将从一个 Greeting POJO开始,它将被我们的RESTful服务序列化为JSON:
src/main/java/hello/Greeting.java

package hello;


public class Greeting 

  private String message;

  public Greeting() 
  

  public Greeting(String message) 
    this.message = message;
  

  public String getMessage() 
    return this.message;
  

  public void setMessage(String message) 
    this.message = message;
  

  @Override
  public String toString() 
    return "Greeting" +
        "message='" + message + '\\'' +
        '';
  

在 Spring Reactive 方法中,我们使用一个处理程序来处理请求并创建响应,如下所示:
src/main/java/hello/GreetingHandler.java

package hello;

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 GreetingHandler 

  public Mono<ServerResponse> hello(ServerRequest request) 
    return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
      .body(BodyInserters.fromValue(new Greeting("Hello, Spring!")));
  

这个简单的响应式类总是返回一个带有 “Hello, Spring!” “问候。它可以返回许多其他内容,包括从数据库中返回的项流、由计算生成的项流等等。注意反应性代码:保存 ServerResponse 主体的 Mono 对象。

6、创建 Router

在这个应用程序中,我们使用一个路由器来处理我们暴露的唯一路由(/hello),如下所示:
src/main/java/hello/GreetingRouter.java

package hello;

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

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;

@Configuration(proxyBeanMethods = false)
public class GreetingRouter 

  @Bean
  public RouterFunction<ServerResponse> route(GreetingHandler greetingHandler) 

    return RouterFunctions
      .route(GET("/hello").and(accept(MediaType.APPLICATION_JSON)), greetingHandler::hello);
  

7、创建 WebClient

Spring RestTemplate 类本质上是阻塞的。因此,我们不希望在响应式应用程序中使用它。对于响应式应用程序,Spring 提供了 WebClient类,它是非阻塞的。我们使用一个基于 webclient 的实现来消费我们的 RESTful 服务:

src/main/java/hello/GreetingClient.java

package hello;

import reactor.core.publisher.Mono;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class GreetingClient 

  private final WebClient client;

  // Spring Boot auto-configures a `WebClient.Builder` instance with nice defaults and customizations.
  // We can use it to create a dedicated `WebClient` for our component.
  public GreetingClient(WebClient.Builder builder) 
    this.client = builder.baseUrl("http://localhost:8080").build();
  

  public Mono<String> getMessage() 
    return this.client.get().uri("/hello").accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .bodyToMono(Greeting.class)
        .map(Greeting::getMessage);
  


WebClient 类使用响应式特性,以 Mono 的形式保存消息的内容(由getMessage 方法返回)。这是使用函数 API (而不是命令式 API)来链接反应操作符。

适应响应式api可能需要一些时间,但是 WebClient有一些有趣的特性,也可以在传统的 Spring MVC 应用程序中使用。

也可以使用WebClient与非响应式、阻塞式服务通信。

8、使应用程序可执行

我们将使用 main() 方法来驱动应用程序,并从端点获得 Greeting 消息。

src/main/java/hello/Application.java

package hello;

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

@SpringBootApplication
public class Application 

  public static void main(String[] args) 
    ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
    GreetingClient greetingClient = context.getBean(GreetingClient.class);
    // We need to block for the content here or the JVM might exit before the message is logged
    System.out.println(">> message = " + greetingClient.getMessage().block());
  

@SpringBootApplication 是一个方便的注释,它添加了以下所有内容:

  • @Configuration:将类标记为应用程序上下文的 bean 定义源。
  • @EnableAutoConfiguration:告诉 Spring Boot 根据类路径设置、其他 bean 和各种属性设置开始添加bean。例如,如果 spring-webmvc 在类路径上,这个注释将应用程序标记为 web 应用程序,并激活关键行为,例如设置DispatcherServlet
  • @ComponentScan:告诉 Spring 在 hello 包中查找其他组件、配置和服务,让它找到控制器。

main() 方法使用 Spring Boo t的 SpringApplication.run() 方法来启动应用程序。您是否注意到没有一行 XML ,也没有 web.xml文件。这个 web 应用程序是 100% 纯 Java,你不需要处理配置任何管道或基础设施。

9、构建一个可执行的JAR

您可以使用Gradle或Maven从命令行运行应用程序。您还可以构建一个单独的可执行JAR文件,其中包含所有必要的依赖项、类和资源,并运行它。构建一个可执行的jar使得在整个开发生命周期、跨不同的环境等过程中,将服务作为应用程序来交付、版本和部署变得容易。

如果你使用Gradle,你可以使用 ./gradlew boorun 来运行应用程序。或者,你也可以使用 ./gradlew build构建JAR文件,然后运行JAR文件,如下所示:

java -jar build/libs/gs-reactive-rest-service-0.1.0.jar

如果你使用Maven,你可以使用 ./mvnw spring-boot:run 来运行这个应用。或者,您也可以使用 ./mvnw clean 包构建JAR文件,然后运行 JAR 文件,如下所示:

java -jar target/gs-reactive-rest-service-0.1.0.jar

显示日志输出。服务应该在几秒钟内启动并运行。

一旦服务启动,你会看到一行代码:

>> message = Hello, Spring!

这一行来自 WebClient 正在使用的响应式内容。当然,您可以对输出进行更有趣的处理,而不是将其放入 System.out 中。

10、测试应用程序

现在应用程序正在运行,您可以对其进行测试。首先,您可以打开浏览器并访问 http://localhost:8080/hello,并看到 “Hello, Spring!” 在本指南中,我们还创建了一个测试类,让您开始使用 WebTestClient 类进行测试。

src/test/java/hello/GreetingRouterTest.java

package hello;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(SpringExtension.class)
//  We create a `@SpringBootTest`, starting an actual server on a `RANDOM_PORT`
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class GreetingRouterTest 

  // Spring Boot will create a `WebTestClient` for you,
  // already configure and ready to issue requests against "localhost:RANDOM_PORT"
  @Autowired
  private WebTestClient webTestClient;

  @Test
  public void testHello() 
    webTestClient
      // Create a GET request to test an endpoint
      .get().uri("/hello")
      .accept(MediaType.APPLICATION_JSON)
      .exchange()
      // and use the dedicated DSL to test assertions against the response
      .expectStatus().isOk()
      .expectBody(Greeting.class).value(greeting -> 
        assertThat(greeting.getMessage()).isEqualTo("Hello, Spring!");
    );
  

11、总结

恭喜你! 您已经开发了一个响应式 Spring 应用程序,其中包括一个使用RESTful 服务的 WebClient !

想要编写新的指南或对现有指南做出贡献吗?请查看我们的 投稿指南

以上是关于Spring Webflux 构建响应式 Restful Web 服务的主要内容,如果未能解决你的问题,请参考以下文章

Spring Webflux 构建响应式 Restful Web 服务

Spring Webflux 构建响应式 Restful Web 服务

WebFlux+Spring Data Reactive,从头到脚构建一个响应式的微服务

Spring WebFlux快速上手——响应式Spring的道法术器

gateway&reactive(响应式流)函数编程的webflux

Spring Webflux(Mono/Flux) 与 AOP 在拦截时触发 REST 调用并使用 Mono/Flux