1. 程式人生 > 程式設計 >Spring Boot WebFlux 快速入門實踐

Spring Boot WebFlux 快速入門實踐

02:WebFlux 快速入門實踐

Spring Boot 2.0

spring.io 官網有句醒目的話是:

BUILD ANYTHING WITH SPRING BOOT複製程式碼

Spring Boot (Boot 顧名思義,是引導的意思)框架是用於簡化 Spring 應用從搭建到開發的過程。應用開箱即用,只要通過一個指令,包括命令列 java -jarSpringApplication 應用啟動類 、 Spring Boot Maven 外掛等,就可以啟動應用了。另外,Spring Boot 強調只需要很少的配置檔案,所以在開發生產級 Spring 應用中,讓開發變得更加高效和簡易。目前,Spring Boot 版本是 2.x 版本。Spring Boot 包括 WebFlux。

Spring Boot 2.0 WebFlux

瞭解 WebFlux,首先了解下什麼是 Reactive Streams。Reactive Streams 是 JVM 中面向流的庫標準和規範:

  • 處理可能無限數量的元素
  • 按順序處理
  • 元件之間非同步傳遞
  • 強制性非阻塞背壓(Backpressure)

Backpressure(背壓)

背壓是一種常用策略,使得釋出者擁有無限制的緩衝區儲存元素,用於確保釋出者釋出元素太快時,不會去壓制訂閱者。

Reactive Streams(響應式流)

一般由以下組成:

  • 釋出者:釋出元素到訂閱者
  • 訂閱者:消費元素
  • 訂閱:在釋出者中,訂閱被建立時,將與訂閱者共享
  • 處理器:釋出者與訂閱者之間處理資料

響應式程式設計有了 Reactive Streams 這種標準和規範,利用規範可以進行響應式程式設計。那再瞭解下什麼是 Reactive programming 響應式程式設計。響應式程式設計是基於非同步和事件驅動的非阻塞程式,只是垂直通過在 JVM 內啟動少量執行緒擴充套件,而不是水平通過叢集擴充套件。這就是一個程式設計範例,具體專案中如何體現呢?

響應式專案程式設計實戰中,通過基於 Reactive Streams 規範實現的框架 Reactor 去實戰。Reactor 一般提供兩種響應式 API :

  • Mono:實現釋出者,並返回 0 或 1 個元素
  • Flux:實現釋出者,並返回 N 個元素

Spring Webflux

Spring Boot Webflux 就是基於 Reactor 實現的。Spring Boot 2.0 包括一個新的 spring-webflux 模組。該模組包含對響應式 HTTP 和 WebSocket 客戶端的支援,以及對 REST,HTML 和 WebSocket 互動等程式的支援。一般來說,Spring MVC 用於同步處理,Spring Webflux 用於非同步處理。

Spring Boot Webflux 有兩種程式設計模型實現,一種類似 Spring MVC 註解方式,另一種是使用其功能性端點方式。註解的會在第二篇文章講到,下面快速入門用 Spring Webflux 功能性方式實現。

Spring Boot 2.0 WebFlux 特性

常用的 Spring Boot 2.0 WebFlux 生產的特性如下:

  • 響應式 API
  • 程式設計模型
  • 適用性
  • 內嵌容器
  • Starter 元件

還有對日誌、Web、訊息、測試及擴充套件等支援。

響應式 API

Reactor 框架是 Spring Boot Webflux 響應庫依賴,通過 Reactive Streams 並與其他響應庫互動。提供了 兩種響應式 API : Mono 和 Flux。一般是將 Publisher 作為輸入,在框架內部轉換成 Reactor 型別並處理邏輯,然後返回 Flux 或 Mono 作為輸出。

適用性

file

一圖就很明確了,WebFlux 和 MVC 有交集,方便大家遷移。但是注意:

  • MVC 能滿足場景的,就不需要更改為 WebFlux。
  • 要注意容器的支援,可以看看下面內嵌容器的支援。
  • 微服務體系結構,WebFlux 和 MVC 可以混合使用。尤其開發 IO 密集型服務的時候,選擇 WebFlux 去實現。

程式設計模型

Spring 5 web 模組包含了 Spring WebFlux 的 HTTP 抽象。類似 Servlet API,WebFlux 提供了 WebHandler API 去定義非阻塞 API 抽象介面。可以選擇以下兩種程式設計模型實現:

  • 註解控制層。和 MVC 保持一致,WebFlux 也支援響應性 @RequestBody 註解。
  • 功能性端點。基於 lambda 輕量級程式設計模型,用來路由和處理請求的小工具。和上面最大的區別就是,這種模型,全程控制了請求 - 響應的生命流程

內嵌容器

跟 Spring Boot 大框架一樣啟動應用,但 WebFlux 預設是通過 Netty 啟動,並且自動設定了預設埠為 8080。另外還提供了對 Jetty、Undertow 等容器的支援。開發者自行在新增對應的容器 Starter 元件依賴,即可配置並使用對應內嵌容器例項。

但是要注意,必須是 Servlet 3.1+ 容器,如 Tomcat、Jetty;或者非 Servlet 容器,如 Netty 和 Undertow。

Starter 元件

跟 Spring Boot 大框架一樣,Spring Boot Webflux 提供了很多 “開箱即用” 的 Starter 元件。Starter 元件是可被載入在應用中的 Maven 依賴項。只需要在 Maven 配置中新增對應的依賴配置,即可使用對應的 Starter 元件。例如,新增 spring-boot-starter-webflux 依賴,就可用於構建響應式 API 服務,其包含了 Web Flux 和 Tomcat 內嵌容器等。

開發中,很多功能是通過新增 Starter 元件的方式來進行實現。那麼,Spring Boot 2.x 常用的 Starter 元件有哪些呢?

Spring Boot 2.0 WebFlux 元件

Spring Boot WebFlux 官方提供了很多 Starter 元件,每個模組會有多種技術實現選型支援,來實現各種複雜的業務需求:

  • Web:Spring WebFlux
  • 模板引擎:Thymeleaf
  • 儲存:Redis、MongoDB、Cassandra。不支援 MySQL
  • 內嵌容器:Tomcat、Jetty、Undertow

快速入門

Spring Initializr 快速構建專案骨架

Spring Boot Maven 工程,就是普通的 Maven 工程,加入了對應的 Spring Boot 依賴即可。Spring Initializr 則是像程式碼生成器一樣,自動就給你出來了一個 Spring Boot Maven 工程。Spring Initializr 有兩種方式可以得到 Spring Boot Maven 骨架工程:

start.spring.io 線上生成

Spring 官方提供了名為 Spring Initializr 的網站,去引導你快速生成 Spring Boot 應用。網站地址為:https://start.spring.io,操作步驟如下:

第一步,選擇 Maven 或者 Gradle 構建工具,開發語言 Java 、Kotlin 或者 Groovy,最後確定 Spring Boot 版本號。這裡預設選擇 Maven 構建工具、Java 開發語言和 Spring Boot 2.0.1。

第二步,輸入 Maven 工程資訊,即專案組 groupId 和名字 artifactId。這裡對應 Maven 資訊為:

  • groupId:springboot
  • artifactId:sspringboot-webflux-1-quickstart
    這裡預設版本號 version 為 0.0.1-SNAPSHOT 。三個屬性在 Maven 依賴倉庫是唯一標識的。

第三步,選擇工程需要的 Starter 元件和其他依賴。最後點選生成按鈕,即可獲得骨架工程壓縮包。這裡快速入門,只要選擇 Reactive Web 即可。如圖 1-8 所示。

配置 POM 依賴

檢查工程 POM 檔案中,是否配置了 spring-boot-starter-webflux 依賴。如果是上面自動生成的,配置如下:

  <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>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>複製程式碼

spring-boot-starter-webflux 依賴,是我們核心需要學習 webflux 的包,裡面預設包含了 spring-boot-starter-reactor-netty 、spring 5 webflux 包。也就是說預設是通過 netty 啟動的。

reactor-test、spring-boot-starter-test 兩個依賴搭配是用於單元測試。

spring-boot-maven-plugin 是 Spring Boot Maven 外掛,可以執行、編譯等呼叫。

編寫處理器類 Handler

新建包 org.spring.springboot.handler ,作為編寫功能處理類。新建城市(City)例子的處理類 CityHandler,程式碼如下:

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 CityHandler {

    public Mono<ServerResponse> helloCity(ServerRequest request) {
        return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
                .body(BodyInserters.fromObject("Hello,City!"));
    }
}複製程式碼

ServerResponse 是對響應的封裝,可以設定響應狀態,響應頭,響應正文。比如 ok 代表的是 200 響應碼、MediaType 列舉是代表這文字內容型別、返回的是 String 的物件。

這裡用 Mono 作為返回物件,是因為返回包含了一個 ServerResponse 物件,而不是多個元素。

編寫路由器類 Router

新建 org.spring.springboot.router 包,作為編寫路由器類。新建城市(City)例子的路由類 CityRouter,程式碼如下:

import org.spring.springboot.handler.CityHandler;
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 CityRouter {


    @Bean
    public RouterFunction<ServerResponse> routeCity(CityHandler cityHandler) {
        return RouterFunctions
                .route(RequestPredicates.GET("/hello")
                                .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),cityHandler::helloCity);
    }

}複製程式碼

RouterFunctions 對請求路由處理類,即將請求路由到處理器。這裡將一個 GET 請求 /hello 路由到處理器 cityHandler 的 helloCity 方法上。跟 Spring MVC 模式下的 HandleMapping 的作用類似。

RouterFunctions.route(RequestPredicate,HandlerFunction) 方法,對應的入參是請求引數和處理函式,如果請求匹配,就呼叫對應的處理器函式。

到這裡一個簡單的服務就寫好了,下面怎麼執行該服務。

啟動執行專案

一個簡單的 Spring Boot Webflux 工程就開發完畢了,下面執行工程驗證下。使用 IDEA 右側工具欄,點選 Maven Project Tab ,點選使用下 Maven 外掛的 install 命令。或者使用命令列的形式,在工程根目錄下,執行 Maven 清理和安裝工程的指令:

cd springboot-webflux-1-quickstart
mvn clean install複製程式碼

在控制檯中看到成功的輸出:

... 省略
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:30 min
[INFO] Finished at: 2017-10-15T10:00:54+08:00
[INFO] Final Memory: 31M/174M
[INFO] ------------------------------------------------------------------------複製程式碼

執行工程

在 IDEA 中執行 Application 類啟動,任意正常模式或者 Debug 模式。可以在控制檯看到成功執行的輸出:

... 省略
2018-04-10 08:43:39.932  INFO 2052 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext     : Started HttpServer on /0:0:0:0:0:0:0:0:8080
2018-04-10 08:43:39.935  INFO 2052 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2018-04-10 08:43:39.960  INFO 2052 --- [           main] org.spring.springboot.Application        : Started Application in 6.547 seconds (JVM running for 9.851)複製程式碼

一看,確實是 Netty 啟動的。

開啟瀏覽器,訪問 /hello 地址,會看到如圖所示的返回結果:

file

總結

本文主要講了 Spring Boot 2.0 WebFlux 背景和快速入門使用。用的是基於功能性端點去建立一個服務,但這個有點程式碼偏多。下一章一個 CRUD 我們使用註解控制層,讓開發更方便。

本文由部落格一文多發平臺 OpenWrite 釋出!