摘要: 原創出處 https://www.bysocket.com 歡迎關注和轉載,保留摘要,謝謝!
02:WebFlux 快速入門實踐
文章工程:
- JDK 1.8
- Maven 3.5.2
- Spring Boot 2.1.3.RELEASE
- 工程名:springboot-webflux-1-quickstart
- 工程位址:見文末
一、Spring Boot 2.0
spring.io 官網有句醒目的話是:
BUILD ANYTHING WITH SPRING BOOT
Spring Boot (Boot 顧名思義,是引導的意思)架構是用于簡化 Spring 應用從搭建到開發的過程。應用開箱即用,隻要通過一個指令,包括指令行
java -jar
、
SpringApplication
應用啟動類 、 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)
2.1 Backpressure(背壓)
背壓是一種常用政策,使得釋出者擁有無限制的緩沖區存儲元素,用于確定釋出者釋出元素太快時,不會去壓制訂閱者。
2.2 Reactive Streams(響應式流)
一般由以下組成:
- 釋出者:釋出元素到訂閱者
- 訂閱者:消費元素
- 訂閱:在釋出者中,訂閱被建立時,将與訂閱者共享
- 處理器:釋出者與訂閱者之間處理資料
2.3 響應式程式設計
有了 Reactive Streams 這種标準和規範,利用規範可以進行響應式程式設計。那再了解下什麼是 Reactive programming 響應式程式設計。響應式程式設計是基于異步和事件驅動的非阻塞程式,隻是垂直通過在 JVM 内啟動少量線程擴充,而不是水準通過叢集擴充。這就是一個程式設計範例,具體項目中如何展現呢?
響應式項目程式設計實戰中,通過基于 Reactive Streams 規範實作的架構 Reactor 去實戰。Reactor 一般提供兩種響應式 API :
- Mono:實作釋出者,并傳回 0 或 1 個元素
- Flux:實作釋出者,并傳回 N 個元素
2.4 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、消息、測試及擴充等支援。
3.1 響應式 API
Reactor 架構是 Spring Boot Webflux 響應庫依賴,通過 Reactive Streams 并與其他響應庫互動。提供了 兩種響應式 API : Mono 和 Flux。一般是将 Publisher 作為輸入,在架構内部轉換成 Reactor 類型并處理邏輯,然後傳回 Flux 或 Mono 作為輸出。
3.2 适用性
一圖就很明确了,WebFlux 和 MVC 有交集,友善大家遷移。但是注意:
- MVC 能滿足場景的,就不需要更改為 WebFlux。
- 要注意容器的支援,可以看看下面内嵌容器的支援。
- 微服務體系結構,WebFlux 和 MVC 可以混合使用。尤其開發 IO 密集型服務的時候,選擇 WebFlux 去實作。
3.3 程式設計模型
Spring 5 web 子產品包含了 Spring WebFlux 的 HTTP 抽象。類似 Servlet API , WebFlux 提供了 WebHandler API 去定義非阻塞 API 抽象接口。可以選擇以下兩種程式設計模型實作:
- 注解控制層。和 MVC 保持一緻,WebFlux 也支援響應性 @RequestBody 注解。
- 功能性端點。基于 lambda 輕量級程式設計模型,用來路由和處理請求的小工具。和上面最大的差別就是,這種模型,全程控制了請求 – 響應的生命流程
3.4 内嵌容器
跟 Spring Boot 大架構一樣啟動應用,但 WebFlux 預設是通過 Netty 啟動,并且自動設定了預設端口為 8080。另外還提供了對 Jetty、Undertow 等容器的支援。開發者自行在添加對應的容器 Starter 元件依賴,即可配置并使用對應内嵌容器執行個體。
但是要注意,必須是 Servlet 3.1+ 容器,如 Tomcat、Jetty;或者非 Servlet 容器,如 Netty 和 Undertow。
3.5 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
五、快速入門
5.1 Spring Initializr 快速建構項目骨架
Spring Boot Maven 工程,就是普通的 Maven 工程,加入了對應的 Spring Boot 依賴即可。Spring Initializr 則是像代碼生成器一樣,自動就給你出來了一個 Spring Boot Maven 工程。Spring Initializr 有兩種方式可以得到 Spring Boot Maven 骨架工程:
5.1.1 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 所示。
5.2 配置 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 插件,可以運作、編譯等調用。
5.3 編寫處理器類 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 對象,而不是多個元素。
5.4 編寫路由器類 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) 方法,對應的入參是請求參數和處理函數,如果請求比對,就調用對應的處理器函數。
到這裡一個簡單的服務就寫好了,下面怎麼運作該服務。
5.5 啟動運作項目
一個簡單的 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] ------------------------------------------------------------------------
5.5.1 運作工程
在 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 位址,會看到如圖所示的傳回結果:
六、總結
本文主要講了 Spring Boot 2.0 WebFlux 背景和快速入門使用。用的是基于功能性端點去建立一個服務,但這個有點代碼偏多。下一章一個 CRUD 我們使用注解控制層,讓開發更友善。
系列教程目錄
- 《01:WebFlux 系列教程大綱》
- 《02:WebFlux 快速入門實踐》
- 《03:WebFlux Web CRUD 實踐》
- 《04:WebFlux 整合 Mongodb》
- 《05:WebFlux 整合 Thymeleaf》
- 《06:WebFlux 中 Thymeleaf 和 Mongodb 實踐》
- 《07:WebFlux 整合 Redis》
- 《08:WebFlux 中 Redis 實作緩存》
- 《09:WebFlux 中 WebSocket 實作通信》
- 《10:WebFlux 內建測試及部署》
- 《11:WebFlux 實戰圖書管理系統》
代碼示例
本文示例讀者可以通過檢視下面倉庫的中的子產品工程名: 2-x-spring-boot-webflux-handling-errors:
- Github: https://github.com/JeffLi1993/springboot-learning-example
- Gitee: https://gitee.com/jeff1993/springboot-learning-example
如果您對這些感興趣,歡迎 star、follow、收藏、轉發給予支援!
參考資料
- Spring Boot 2.x WebFlux 系列:https://www.bysocket.com/archives/2290
- spring.io 官方文檔
以下專題教程也許您會有興趣
- 《Spring Boot 2.x 系列教程》 https://www.bysocket.com/springboot
- 《Java 核心系列教程》 https://www.bysocket.com/archives/2100