不知道有沒有小夥伴因爲調用服務中的種種問題,如:調用異常、結果未返回、網絡抖動等等,需要進行重試而困擾過。java的重試機制有很多種,今天咱們一起學習一下Spring-Retry。
什麼是Spring Retry
Spring Retry爲Spring應用程序提供聲明式重試支持,我們可以使用@Retryable和@Recover,快捷的實現重試和補償策略。
Spring Retry GitHub地址
https://github.com/spring-projects/spring-retry
Spring Retry 實例
1、添加pom依賴
<!-- retry重試 依賴 -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
2、SpringbootMysqlMybatisDemoApplication 啓動類加上@EnableRetry註解
package com.example.demo.smm;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
@SpringBootApplication
@EnableRetry
public class SpringbootMysqlMybatisDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMysqlMybatisDemoApplication.class, args);
}
}
3、在需要的方法上加上@Retryable 和 @Recover註解
//最大重試3次,每次重試延遲2s->3s->4.5s
@Retryable(include = RuntimeException.class, maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
@Override
public UserInfo getHttpReTryTest(Integer num) throws Exception {
num ++;
if(num > 1) {
System.out.println("運行getHttpReTryTest方法--------------------");
throw new RuntimeException("強制拋出異常,getUserInfoByIdReTryTest num:" + num);
} else {
System.out.println("運行getHttpReTryTest方法********************");
throw new IOException("強制拋出異常,getUserInfoByIdReTryTest num:" + num);
}
}
//最大重試3次,每次重試延遲2s->3s->4.5s
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 20000,maxDelay = 80000, multiplier = 2))
@Override
public Long insertHttpReTryTest(UserInfo userInfo) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd : HH:mm:ss");
System.out.println("調用http方法:" + simpleDateFormat.format(new Date()));
throw new RuntimeException("強制拋出異常,insertHttpReTryTest result:" + userInfo.toString());
}
@Recover
public UserInfo getHttpReTryTestRuntimeException(RuntimeException e) {
System.out.println("調用getHttpReTryTestRuntimeException方法 e:" + e.getMessage());
return new UserInfo();
}
@Recover
public UserInfo getHttpReTryTestIOException(IOException e) {
System.out.println("getHttpReTryTestIOException e:" + e.getMessage());
return new UserInfo();
}
@Recover
public Long insertHttpReTryTestException(RuntimeException e) {
System.out.println("調用insertHttpReTryTestException方法 e:" + e.getMessage());
return 0L;
}
Spring Retry 註解屬性詳解
1、@EnableRetry 作用於SpringbootApplication啓動類,開啓spring retry。
proxyTargetClass:默認值爲false,設置爲true時爲CGLIB代理。
2、@Retryable 作用於需要進行重試的方法
value:指定處理的異常類,默認爲空
include:指定處理的異常類,默認爲空,當include和exclude爲空時,默認所有異常
exclude:指定哪些異常不處理,默認空
maxAttempts:最大重試次數。默認3次
backoff: 重試補償策略。默認使用@Backoff註解
3、@Backoff 作用於backoff中的補償策略
delay:指定等待時間,沒有設置的話默認爲1000ms
maxDelay:最大重試時間,沒有設置默認爲3000ms
multiplier:下一次調用時間的乘數
random:隨機等待時間,默認值爲false
4、@Recover 用於對retry方法的異常拋出的特殊處理,可做熔斷、降級、日誌等操作。入參必須和retry對應方法所拋出的異常類型相同。
注意點
1、因爲maxDelay的默認值爲30000ms,沒有設置時,要注意自己的最大重試時間是否會超過30000ms,如下:
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 20000, multiplier = 2))
把maxDelay設置爲80000ms後,第三次調用間隔爲預期的40000ms
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 20000,maxDelay = 80000, multiplier = 2))
2、如果需要隨機重試值,開啓random,效果如下:
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(maxDelay = 80000, multiplier = 2,random = true))
3、本質上retry是使用的aop切面,所以要注意aop的一些問題,在retry也會出現,如內嵌調用失效等。
4、重試時要注意接收者是否有做冪等操作,支持重試。
以上爲Spring Retry的使用內容,使用Retry可以讓我們快捷方便的實現各種重試方式。