Spring Webflux 中拋出異常和 Mono.error() 的區別
1. 概述
錯誤處理是 Spring WebFlux 反應式程式設計的關鍵面向。開發人員通常依賴兩種主要方法進行錯誤處理:拋出例外或使用 Project Reactor 提供的Mono.error()
方法。這兩種方法都用於發出錯誤信號,但它們具有不同的特徵和用例。
在本教程中,我們將解釋 Spring WebFlux 中拋出異常和Mono.error()
之間的差異。我們將提供說明性 Java 程式碼範例以使其更容易理解。
2. 傳統方法:拋出例外
多年來,拋出異常一直是 Java 應用程式中管理錯誤的可靠方法。這是一種中斷程式常規流程並將錯誤傳遞給應用程式更高層的簡單方法。 Spring WebFlux 與此傳統的錯誤處理方法順利集成,使開發人員能夠在其反應端點中拋出異常。下面的程式碼代表了傳統方法的範例:
public Mono<User> getUserByIdThrowingException(String id) {
User user = userRepository.findById(id);
if (user == null) {
throw new NotFoundException("User Not Found");
}
return Mono.justOrEmpty(user);
}
在此特定場景中, getUserByIdThrowingException()
方法嘗試根據UserRepository
提供的 ID 檢索使用者資料。如果找不到用戶,方法會拋出NotFoundException
,這會在反應式管道中發出錯誤訊號。
為了執行單元測試,我們從org.junit.jupiter.api.Assertions
導入assertThrows
方法。此測試getUserByIdThrowingException()
是否為資料庫中找不到的使用者拋出NotFoundException
。我們使用帶有 lambda 的assertThrows
來執行應該拋出異常的方法呼叫。
如果引發異常,程式碼將驗證引發的異常是否屬於預期類型。但是,如果該方法沒有拋出異常,則測試失敗:
@Test
public void givenNonExistUser_whenFailureCall_then_Throws_exception() {
assertThrows(
NotFoundException.class,
() -> userService.getUserByIdThrowingException("3")
);
}
3.擁抱反應性: Mono.error()
與拋出異常的傳統方法相比,Project Reactor 透過Mono.error()
方法引入了反應式替代方法。此方法產生一個 Mono,該 Mono 會立即以錯誤訊號終止,與反應式程式範例無縫對齊。
讓我們使用Mono.error()
檢查修改後的範例:
public Mono<User> getUserByIdUsingMonoError(String id) {
User user = userRepository.findById(id);
return (user != null)
? Mono.justOrEmpty(user)
: Mono.error(new NotFoundException("User Not Found"));
}
為了保持流暢的使用者體驗和一致的反應流程,我們使用Mono.error()
而不是直接為資料庫中找不到的使用者拋出例外。
這是此方法的單元測試:
@Test
public void givenNonExistUser_whenFailureCall_then_returnMonoError() {
Mono result = userService.getUserByIdUsingMonoError("3");
StepVerifier.create(result)
.expectError(NotFoundException.class)
.verify();
}
4. 了解主要差異和用例
4.1.控制流程中斷
當Mono.error()
發出訊號時,我們將異常與 try-catch 或反應式運算子(如onErrorResume
、 onErrorReturn
或onErrorMap
一起使用。
4.2.懶惰
Mono.error()
現在支援異常的延遲實例化,這在構造異常涉及資源密集型操作的場景中非常有用。
4.3.反應性錯誤處理
Mono.error()
與反應式程式設計範例很好地結合在一起,促進反應式流中的反應式錯誤處理。
5. 結論
在本文中,我們討論了在 Spring WebFlux 中拋出異常和利用Mono.error()
進行響應式應用程式中的錯誤處理之間的根本區別;儘管這兩種方法都具有相同的訊號錯誤目的,但它們在控制流程以及與反應式管道的整合方面存在顯著差異。
引發異常會中斷執行流程並將控制權轉移到最近的異常處理程序,使其適合命令式程式碼路徑。相反, Mono.error()
與反應流無縫集成,無需停止執行流即可實現非同步錯誤訊號。
使用 Spring WebFlux 開發響應式應用程式時,根據上下文和需求選擇正確的錯誤處理機制至關重要。我們在反應式管道中使用Mono.error()
來保持其反應性,並使用命令式程式碼路徑的異常。與往常一樣,本教學的源代碼可在 GitHub 上取得。