非同步響應式程式設計可以極大的提高系統的併發呑吐量,但由於Java沒有類似於其他語言的Async/Await機制,所以只能通過CompletableFuture.thenXXX()來串聯各個非同步任務,這給習慣了寫同步增刪改查的小夥伴們帶來了些小麻煩。如果說C#基於狀態機在編譯時實現了await轉換,那麼Java肯定也可以基於相同的原理實現await,作者上網一搜果然找到了ea-async,使用與C#相同的方式實現了await非同步方法,這回終於可以愉快的擼Java非同步程式碼了。
一、 示例程式碼
舉個扣減庫存並儲存訂單的例子,在沒有await方式下的示例程式碼如下:
public CompletableFuture<?> saveOrder(Order order) {
//1.開始事務
return DataStore.DemoDB.beginTransaction().thenCompose(txn -> {
//2.扣庫存
var cmd = new SqlUpdateCommand<Order>();
cmd.update(e -> e.Stock = e.Stock - order.Quantity); //當前量扣除訂單量
cmd.where(e -> e.ProductId == order.ProductId);
var outs = cmd.output(e -> e.Stock);
return cmd.execAsync(txn).thenCompose(rows -> {
//3.判斷庫存
if (rows == 0 || outs.get(0) < 0)
return CompletableFuture.failedFuture("庫存不足");
//4.儲存訂單
return order.saveAsync(txn);
}).thenCompose(r -> txn.commitAsync()); //5.遞交事務
}).thenApply(r -> "Done.");
}
WTF! 一層套一層的回撥,這還只是個簡單的例子啊。但是如果使用await的方式,業務邏輯就變得清爽多了:
import static sys.Async.await;
public CompletableFuture<?> saveOrder(Order order) {
//1.開始事務
var txn = await(DataStore.DemoDB.beginTransaction());
//2.扣庫存
var cmd = new SqlUpdateCommand<Order>();
cmd.update(e -> e.Stock = e.Stock - order.Quantity); //當前量扣除訂單量
cmd.where(e -> e.ProductId == order.ProductId);
var outs = cmd.output(e -> e.Stock);
var rows = await(cmd.execAsync(txn));
//3.判斷庫存
if (rows == 0 || outs.get(0) < 0)
return CompletableFuture.failedFuture("庫存不足");
//4.儲存訂單
await(order.saveAsync(txn));
//5.遞交事務
await(txn.commitAsync());
return CompletableFuture.completedFuture("Done.");
}
二、 實現原理
核心思想沒有變,還是程式碼分析轉換。作者原本想利用JDT在原始碼層進行await轉換,但是工作量還是比較大的,在這裡感謝github/ea-async專案,使得作者只修改了十幾行程式碼就實現了上述效果,具體轉換過程如下:
- 服務模型的虛擬程式碼經過JDT分析、轉換、編譯為class檔案(參考前篇說明);
- 呼叫ea-async的Transformer類直接分析與轉換class檔案內的await方法呼叫,生成新的class檔案。
具體參考原始碼PublishService的compileService()及transformAsync()方法。
三、 本篇小結
先解釋一下上篇"優雅的Java ORM"小夥伴們的評論,有說這麼多ORM幹嗎還要造一個的,也有說不夠"優雅"的,其實造輪子最根本的原因是:非同步支援!,Spring WebFlux及VertX有相應的非同步運算元據庫的支援,但本框架沒法整合。MyBatis之類的全是同步操作,小的應用系統沒有問題,高併發系統的呑吐量就非常可憐了,這個大家可以測一下Spring MVC與WebFlux的效能對比。
軟體技術日新月異,新一代的開發框架必定是非同步的!對於作者來講Spring還不夠簡單優雅,執行的也不夠快,所以才會嘗試重新造這個大輪子,爭取讓應用系統的開發人員有更多的時間關注資料結構、業務邏輯和使用者體驗,也爭取讓小夥伴們有一個絲般順滑的開發體驗。
邊碼程式碼邊碼文實屬不易,作者需要您的支援請您多多點贊推薦!另歡迎感興趣的小夥伴加入我們!