今天小編為大家帶來的是社群作者六七十三的文章,讓我們一起來學習Spring Boot 整合 Reactor。
Reactor 是一個完全非阻塞的 JVM 響應式程式設計基礎,有著高效的需求管理(背壓的形式)。它直接整合 Java8 的函式式 API,尤其是
CompletableFuture, Stream,
還有
Duration
。提供了可組合的非同步化序列 API — Flux (對於 [N] 個元素) and Mono (對於 [0|1] 元素) — 並廣泛實現 響應式Stream 規範。
這次帶大家從零開始,使用 Spring Boot 框架建立一個 Reactor 響應式專案。
1 建立專案
使用
https://start。spring。io/
建立專案。新增依賴項:H2、Lombok、Spring Web、JPA、JDBC
然後匯入 Reactor 包
2 整合 H2 資料庫
application。properties
檔案中新增 H2 資料連線資訊。此外,埠使用 8081(隨意,本地未被使用的埠即可)。
server。port=8081################ H2 資料庫 基礎配置 ##############spring。datasource。driverClassName=org。h2。Driverspring。datasource。url=jdbc:h2:~/userspring。datasource。username=saspring。datasource。password=spring。jpa。database=h2spring。jpa。hibernate。ddl-auto=updatespring。h2。console。path=/h2-consolespring。h2。console。enable=true
3 建立測試類
3。1 user 實體
建立簡單資料操作實體 User。
import lombok。Data;import lombok。NoArgsConstructor;import javax。persistence。*;/** * @Author: prepared * @Date: 2022/8/29 21:40 */@Data@NoArgsConstructor@Table(name = “t_user”)@Entitypublic class User { @Id @GeneratedValue(strategy = GenerationType。AUTO) private Long id; private String userName; private int age; private String sex; public User(String userName, int age, String sex) { this。userName = userName; this。age = age; this。sex = sex; }}
3。2 UserRepository
資料模型層使用 JPA 框架。
import com。prepared。user。domain。User;import org。springframework。data。jpa。repository。JpaRepository;import org。springframework。stereotype。Repository;/** * @Author: prepared * @Date: 2022/8/29 21:45 */@Repositorypublic interface UserRepository extends JpaRepository
3。3 UserService
service 增加兩個方法,add 方法,用來新增資料;list 方法,用來查詢所有資料。所有介面返回 Mono/Flux 物件。
最佳實踐:所有的第三方介面、IO 耗時比較長的操作都可以放在 Mono 物件中。
doOnError
監控異常情況;
doFinally
監控整體執行情況,如:耗時、呼叫量監控等。
import com。prepared。user。dao。UserRepository;import com。prepared。user。domain。User;import org。slf4j。Logger;import org。slf4j。LoggerFactory;import org。springframework。stereotype。Service;import reactor。core。publisher。Mono;import javax。annotation。Resource;import java。util。List;/** * @Author: prepared * @Date: 2022/8/29 21:45 */@Servicepublic class UserService { private Logger logger = LoggerFactory。getLogger(UserService。class); @Resource private UserRepository userRepository; public Mono> list() { long startTime = System。currentTimeMillis(); return Mono。fromSupplier(() -> { return userRepository。findAll(); })。doOnError(e -> { // 列印異常日誌&增加監控(自行處理) logger。error(“list。user。error, e”, e); }) 。doFinally(e -> { // 耗時 & 整體健康 logger。info(“list。user。time={}, ”, System。currentTimeMillis() - startTime); }); } public Flux
3。4 UserController
controller
增加兩個方法,add 方法,用來新增資料;list 方法,用來查詢所有資料。
list 方法還有另外一種寫法,這就涉及到 Mono 和 Flux 的不同了。
返回
List
可以使用
Mono>
,也可以使用
Flux
。
Mono
是一個特定的
Publisher
,最多可以發出一個元素
Flux
是一個標準的
Publisher
,表示為發出 0 到 N 個元素的非同步序列
import com。prepared。user。domain。User;import com。prepared。user。service。UserService;import org。springframework。web。bind。annotation。RequestMapping;import org。springframework。web。bind。annotation。RestController;import reactor。core。publisher。Mono;import javax。annotation。Resource;import java。util。ArrayList;import java。util。List;/** * @Author: prepared * @Date: 2022/8/29 21:47 */@RestControllerpublic class UserController { @Resource private UserService userService; @RequestMapping(“/add”) public Mono> list() { return userService。list(); }} @RequestMapping(“/listFlux”) public Flux
3。5 SpringReactorApplication 添加註解支援
Application 啟動類添加註解 @EnableJpaRepositories
import org。springframework。boot。SpringApplication;import org。springframework。boot。autoconfigure。SpringBootApplication;import org。springframework。data。jpa。repository。config。EnableJpaRepositories;/** * Hello world! */@SpringBootApplication@EnableJpaRepositoriespublic class SpringReactorApplication { public static void main(String[] args) { SpringApplication。run(SpringReactorApplication。class, args); }}
測試
啟動專案,訪問
localhost:8081/add
,正常返回 true。
查詢所有資料,訪問
localhost:8081/list
,可以看到插入的資料,已經查詢出來了。PS:我這裡執行了多次 add,所以有多條記錄。
後臺日誌:
2022-09-05 20:13:17。385 INFO 15696 ——- [nio-8082-exec-2] com。prepared。user。service。UserService : list。user。time=181, 執行了 UserService list() 方法的 doFinnally 程式碼塊,列印耗時日誌。
總結
響應式程式設計的優勢是不會阻塞。那麼正常我們的程式碼中有哪些阻塞的操作呢?
Future 的 get() 方法;
Reactor 中的 block() 方法,subcribe() 方法,所以在使用 Reactor 的時候,除非編寫測試程式碼,否則不要直接呼叫以上兩個方法;
同步方法呼叫,所以高併發情況下,會使用非同步呼叫(如Future)來提升響應速度。
下一篇,講解如何將熔斷、限流框架 resilience4j 整合到專案中,敬請期待。