JAVA如何優雅的重試?@Retryable(spring的重試機制)

楔子

在應用程序中,由於一些網絡等不可預知的問題,我們的程序或者接口會失敗,比如調用一個第三方的接口獲取數據失敗了,這時就需要重試機制,比如延時3S後重試、間隔不斷增加重試等,而這些機制完全不需要你自己去實現,全部交給Spring Retry吧。

使用

1.在pom文件中添加相應的依賴
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.2.2.RELEASE</version>
</dependency>

最新版本可以在Maven Central找到
Spring Retry使用AOP實現,所以必須要有spring-aspects依賴,

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
</dependency>
2.在啓動類或者配置類上添加註解@EnableRetry

配置類

@Configuration
@EnableRetry
public class AppConfig { ... }

啓動類

@SpringBootApplication
@EnableRetry
public class Application
3. 在需要重試的方法上添加註解@Retryable
@Service
public class DemoService {
@Retryable(value= {Exception.class},maxAttempts = 3)
    public void call() throws Exception {
            System.out.println("do something...");
            throw new Exception("RPC調用異常");
    }
    @Recover
    public void recover(RemoteAccessException e) {
            System.out.println(e.getMessage());
    }
}
@Retryable(maxAttempts = 3, backoff = @Backoff(value = 3000, multiplier = 1.5))
public Customer getCustomer(String customerId) {
		if (true) {
			JSONArray data = retObj.getJSONArray("data");
			if (data != null && !data.isEmpty()) {
				return data.toJavaList(Customer.class).get(0);
			}
		} else {
			log.error("異常,{}", customerId);
			throw new RuntimeException("獲數據失敗");
		}
		return null;
}

@Retryable被註解的方法發生異常時會重試

@Retryable註解中的參數說明:
maxAttempts :最大重試次數,默認爲3,如果要設置的重試次數爲3,可以不寫;
value:拋出指定異常纔會重試
include:和value一樣,默認爲空,當exclude也爲空時,所有異常都重試
exclude:指定不處理的異常,默認空,當include也爲空時,所有異常都重試
backoff:重試等待策略,默認使用@Backoff@Backoff的value默認爲1000L,我們設置爲2000L。

@Backoff重試補償機制,默認沒有

@Backoff註解中的參數說明:
value:隔多少毫秒後重試,默認爲1000L,我們設置爲3000L;
delay:和value一樣,但是默認爲0;
multiplier(指定延遲倍數)默認爲0,表示固定暫停1秒後進行重試,如果把multiplier設置爲1.5,則第一次重試爲2秒,第二次爲3秒,第三次爲4.5秒。

4. 可以在指定方法上標記@Recover來開啓重試失敗後調用的方法(注意,需跟重處理方法在同一個類中)

@Recover
當重試到達指定次數時,被註解的方法將被回調,可以在該方法中進行日誌處理。需要注意的是發生的異常和入參類型一致時纔會回調。

5. 採坑提示
  • 1、由於retry用到了aspect增強,所有會有aspect的坑,就是方法內部調用,會使aspect增強失效,那麼retry當然也會失效。參考改鏈接
public class demo {
    public void A() {
        B();
    }

    //這裏B不會執行
    @Retryable(Exception.class)
    public void B() {
        throw new RuntimeException("retry...");
    }
}
  • 2、重試機制,不能在接口實現類裏面寫。所以要做重試,必須單獨寫個service。
  • 3、maxAttemps參數解釋的是說重試次數,但是我再打斷點的時候發現這個=1時,方法一共只執行了一次。

參考文獻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章