異步響應式編程可以極大的提高系統的併發呑吐量,但由於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還不夠簡單優雅,運行的也不夠快,所以纔會嘗試重新造這個大輪子,爭取讓應用系統的開發人員有更多的時間關注數據結構、業務邏輯和用戶體驗,也爭取讓小夥伴們有一個絲般順滑的開發體驗。
邊碼代碼邊碼文實屬不易,作者需要您的支持請您多多點贊推薦!另歡迎感興趣的小夥伴加入我們!