使用背景
在實際工作過程中,因網絡波動、服務並發限制等原因造成接口服務調用失敗,MQ發送消息失敗等,可以采取重試手段,重試機制是常見的一種處理問題的手段。
重試方式有很多,如可以自己通過代碼邏輯實現,但不是很優雅。
而spring-retry可以以優雅的方式實現重試:
Retry重試框架,支持AOP切入的方式使用,而且能使用注解;像我們關心的重試次數、重試延遲時間、重試觸發條件、重試的回調方法等等都能很輕松結合注解以一種類似配置參數的方式去實現,優雅無疑。
本文章簡述springboot+retry的使用。
1、添加依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.jia</groupId>
<artifactId>bill</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>bill</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 重試依賴-->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId >
<artifactId>aspectjweaver</artifactId >
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、在啟動類上加@EnableRetry注解,表示啟動重試機制
1 package com.jia.bill; 2
3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.retry.annotation.EnableRetry; 6
7 @EnableRetry 8 @SpringBootApplication 9 public class BillApplication { 10
11 public static void main(String[] args) { 12 SpringApplication.run(BillApplication.class, args); 13 } 14
15 }
3、定義一個簡單的需要重試的接口服務
package com.jia.bill.service; public interface TestRetryService { int retryServiceTest(int code) throws Exception; }
package com.jia.bill.service.serviceImpl;
import com.jia.bill.service.TestRetryService;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import java.time.LocalTime;
@Service
public class TestRetryServiceImpl implements TestRetryService {
@Override
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
public int retryServiceTest(int code) throws Exception{
System.out.println("retryServiceTest被調用,時間:"+ LocalTime.now());
if (code==0){
throw new Exception("請求參數為0,出現異常");
// throw new IllegalArgumentException("非法數據");
}
System.out.println("retryServiceTest被調用,情況對頭了!");
return 200;
}
@Recover
public int recover(Exception e){
System.out.println("重試次數結束后還有異常,回調方法開始執行");
//可調用其余的方法
return 400;
}
}
當調用TestRetryServiceImpl 中的retryServiceTest時,如果拋出了異常Exception,就會被重試,重試3次。
但是如果三次都失敗了,並且寫了recover方法時,就會執行recover方法了。如果沒有此方法會直接拋出異常。
其中注解解釋:
@Retryable : 注解方式標記當前方法會使用重試機制
里面的 value: 重試的觸發機制,當遇到Exception異常的時候,觸發;
maxAttempts: 重試的次數(包括第一次調用,也就是說如果設置3次,調用一次后,如果一直失敗觸發重試,那么還當前方法還會調用2次);
delay:重試的延遲時間,也就是距離上一次重試方法調用的間隔,單位毫秒
multiplier: delay間隔時間的倍數,也就是說,第一次重試間隔如果是2000ms,那第二次重試的時候就是2000ms 乘以這個倍數1.5,就是3000ms;
maxDelay:重試次數之間的最大時間間隔,默認為0,即忽略,如果小於delay的設置,則默認為30000L;
@Recover,也就是用注解方式標記當期方法為回調方法,可以看到傳參里面寫的是 Exception e,這個是作為回調的接頭暗號(重試次數用完了,還是失敗,我們拋出這個Exception e通知觸發這個回調方法)。
4、controller簡單編寫
package com.jia.bill.controller; import com.jia.bill.service.TestRetryService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestRetryController { @Autowired TestRetryService testRetryServiceImpl; @GetMapping("/testRetry") public String testRetry() throws Exception { int code = 0; int result = testRetryServiceImpl.retryServiceTest(code); return "result:" + result; } }
5、運行結果
retryServiceTest,時間:19:12:24.590 retryServiceTest,時間:19:12:26.591 retryServiceTest,時間:19:12:29.592 重試次數結束后還有異常,回調方法開始執行
