本文翻譯自國外論壇 medium,原文地址:https://levelup.gitconnected.com/how-i-deleted-more-than-1000-lines-of-code-using-spring-retry-9118de29060 > 使用 Spring Retry 重構代 ...
本文翻譯自國外論壇 medium,原文地址:https://levelup.gitconnected.com/how-i-deleted-more-than-1000-lines-of-code-using-spring-retry-9118de29060
使用 Spring Retry 重構代碼的綜合指南。
問題介紹
在我的日常工作中,我主要負責開發一個龐大的金融應用程式。當客戶發送請求時,我們使用他們的用戶 ID 從第三方服務獲取他們的帳戶信息,保存交易並更新緩存中的詳細信息。儘管整個流程看起來足夠簡單,但這些下游系統中的每一個都是不可靠的。我們必須在每一層上實現重試,並且我們必須以一種可以控制重試次數和每次重試之間的延遲的方式來實現,這樣我們就不會超載下游系統。由於我無法共用實際代碼,我會創建一個演示系統來做簡單表示:
由於我們必須在每一層上實現重試,因此我們必須編寫大量樣板代碼,這不僅容易出錯,而且難以維護。由於每個下游系統都有自己的重試要求,因此我們最終添加了越來越多的代碼,最終就像在現有垃圾之上添加垃圾一樣。隨著時間的推移,代碼變得非常脆弱,即使是很小的變化也會破壞整個系統。
推薦博主開源的 H5 商城項目waynboot-mall,這是一套全部開源的微商城項目,包含三個項目:運營後臺、H5 商城前臺和服務端介面。實現了商城所需的首頁展示、商品分類、商品詳情、商品 sku、分詞搜索、購物車、結算下單、支付寶/微信支付、收單評論以及完善的後臺管理等一系列功能。 技術上基於最新得 Springboot3.0、jdk17,整合了 MySql、Redis、RabbitMQ、ElasticSearch 等常用中間件。分模塊設計、簡潔易維護,歡迎大家點個 star、關註博主。
github 地址:https://github.com/wayn111/waynboot-mall
解決方案
為瞭解決這個問題我們決定使用 Spring Retry。
Spring Retry 項目地址:https://github.com/spring-projects/spring-retry
Spring Retry 是 Spring Batch 的一個子項目,它提供了一組註解和介面,我們可以使用它們向代碼添加重試邏輯。它提供了一種向代碼添加重試邏輯的聲明性方法。
作為本文的一部分,我們將瞭解如何使用 Spring Retry 重寫現有代碼,以及它如何幫助我將代碼庫減少 1000 行。在展示新代碼時,我將解釋每個代碼的註解和用例。
在研究重構的代碼之前,讓我們先瞭解一下在項目中設置 Spring 重試所涉及的步驟。
Let’s start hacking!
1. 設置 Spring 重試
將以下依賴項添加到我們的 pom.xml 文件中:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
- 在 spring 配置上啟用 Spring 重試,並使用以下註解:
@Configuration
@EnableRetry
public class ApplicationConfig { }
2. 重構代碼
既然我們已經設置了 Spring Retry,那麼讓我們開始重構代碼。
- 以下是一個查詢用戶全名的代碼示例,左邊是老代碼,右邊是使用了 Spring Retry 的新代碼。
使用 @Retryable 註解,我們通過 retryFor 屬性指定要重試的異常數組,使用 maxAttempts 屬性,可以指定要重試的次數。
- 具有指數退避的緩存重試
一下圖片是一個添加緩存的代碼示例中,我指定要在 JedisConnectionException 上重試,每次重試之間的延遲應為 1000 毫秒,並且延遲應呈指數增長。
使用 @Retryable 註解,我們可以使用重試退避 backoff 屬性,還可以指定每次重試之間的延遲 delay。
- 外部化重試配置
我們可以輕鬆地將重試配置外部化到屬性文件中。當我們想要重用配置並更改它們而無需重新部署應用程式時,這非常有用。就我而言,我創建了一個 retry.properties 文件並添加了以下屬性:
retry.maxAttempts=2
在我的 spring 配置中包含屬性文件:
// <<Other annotations>>
@PropertySource("classpath:retryConfig.properties")
public class ApplicationConfig { }
以下圖片是一個先獲取 MySql 連接,再查數據的例子,我再代碼中使用了該外部化配置屬性:
- 消除錯誤時的重覆操作,使用 RetryListenerSupport 重試
在前面的先獲取 MySql 連接,再查數據的例子中,我想獲取以下事件的指標:
- 連接 MySql 資料庫時,發出指標
- 連接 MySql 資料庫失敗時,發出指標
- 當用盡所有重試次數時,發出指標
再 Spring Retry 中,我可以使用 RetryListenerSupport 將所有代碼添加到一個位置,而不是在連接到 Mysql 資料庫的所有代碼的每個重試塊中添加相同的代碼。
使用 RetryTemplate 上的 registerListener 方法註冊 RetryListenerSupport:
@Configuration
public class ApplicationConfig {
@Bean
public RetryTemplate installTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.registerListener(new DefaultListenerSupport());
return retryTemplate;
}
}
RetryListenerSupport 提供了三種方法,我們可以重寫它們來添加自定義邏輯:
- onError — 當出現錯誤時調用此方法
- close——當所有重試都用盡時調用該方法
- open — 重試開始時調用該方法
現在讓我們看看重構後的代碼:
總結
在本文中,我們瞭解瞭如何使用 Spring Retry 來減少樣板代碼並使代碼更具可讀性和可維護性。通過 Spring Retry,相信你也能夠消除超過 1000 行代碼。
關註公眾號【waynblog】每周分享技術乾貨、開源項目、實戰經驗、高效開發工具等,您的關註將是我的更新動力!