springboot-retry
前言
在我們日常開發中,會遇到比如A服務調用B服務RPC超時、獲取鎖失敗等場景,我們需要進行重試操作,爲了不侵入代碼優雅的進行重試,我們可以利用
Spring
提供的spring-retry
組件來實現。
開始
- 引入依賴
核心依賴spring-retry
,另外因爲spring的retry底層是以AOP實現的,我們也需要引入aspectj
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
- 開啓
@EnableRetry
支持
@EnableRetry
支持方法和類、接口、枚舉級別的重試
@SpringBootApplication
@EnableRetry
public class SpringbootRetryApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootRetryApplication.class, args);
}
}
- 編寫重試service服務
@Retryable
參數說明:
- value:指定異常進行重試
- maxAttempts:重試次數,默認3次
- backoff:補償策略
- include:和value一樣,默認空,當exclude也爲空時,所有異常都重試
- exclude:指定異常不重試,默認空,當include也爲空時,所有異常都重試
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.remoting.RemoteTimeoutException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
/**
* @author lb
*/
@Service
public class RetryService {
private static final Logger LOGGER = LoggerFactory.getLogger(RetryService.class);
@Retryable(
// 指定發生的異常進行重試
value = {RemoteAccessException.class, RemoteTimeoutException.class} ,
// 重試次數
maxAttempts = 3,
// 補償策略 delay:延遲多久執行補償機制,multiplier:指定延遲的倍數,比如delay=5000,multiplier=2時,第一次重試爲5秒後,第二次爲10秒,第三次爲20秒
backoff = @Backoff(delay = 5000L,multiplier = 2)
)
public String call(){
LOGGER.info("執行重試方法.....");
// throw new RemoteAccessException("RPC訪問異常");
throw new RemoteTimeoutException("RPC調用超時異常");
}
@Recover
public String recover(RemoteAccessException e){
LOGGER.info("最終重試失敗,執行RemoteAccess補償機制 error : {}",e.getMessage());
return "ok";
}
@Recover
public String recover(RemoteTimeoutException e){
LOGGER.info("最終重試失敗,執行RemoteTimeout補償機制 error : {}",e.getMessage());
return "ok";
}
}
有幾點需要注意的地方:
- 重試機制的
service
服務必須單獨創建一個class
,不能寫在接口的實現類裏,否則會拋出ex @Retryable
是以AOP實現的,所以如果@Retryable
標記的方法被其他方法調用了,則不會進行重試。recover
方法的返回值類型必須和call()
方法的返回值類型一致
測試
- 編寫測試類
import com.lb.springboot.retry.service.RetryService;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootRetryApplicationTests {
@Autowired
private RetryService retryService;
@Test
public void testRetry(){
String result = retryService.call();
MatcherAssert.assertThat(result, Matchers.is("ok"));
}
}
- 執行結果:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.4.RELEASE)
2020-12-17 14:15:58.083 INFO 71362 --- [ main] c.l.s.r.SpringbootRetryApplicationTests : Starting SpringbootRetryApplicationTests on yunnashengdeMacBook-Pro.local with PID 71362 (started by yunnasheng in /Users/yunnasheng/work/github-workspace/springboot-retry)
2020-12-17 14:15:58.086 INFO 71362 --- [ main] c.l.s.r.SpringbootRetryApplicationTests : No active profile set, falling back to default profiles: default
2020-12-17 14:15:59.238 INFO 71362 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-12-17 14:15:59.470 INFO 71362 --- [ main] c.l.s.r.SpringbootRetryApplicationTests : Started SpringbootRetryApplicationTests in 1.686 seconds (JVM running for 2.582)
2020-12-17 14:15:59.668 INFO 71362 --- [ main] c.l.s.retry.service.RetryService : 執行重試方法.....
2020-12-17 14:16:04.674 INFO 71362 --- [ main] c.l.s.retry.service.RetryService : 執行重試方法.....
2020-12-17 14:16:14.675 INFO 71362 --- [ main] c.l.s.retry.service.RetryService : 執行重試方法.....
2020-12-17 14:16:14.676 INFO 71362 --- [ main] c.l.s.retry.service.RetryService : 最終重試失敗,執行RemoteTimeout補償機制 error : RPC調用超時異常