特别鳴謝:https://blog.csdn.net/Revivedsun/article/details/53401335
參考方式:以下内容都是demo,直接複制粘貼到項目中即可。
1.自定義手寫重試機制
參考位址:https://blog.csdn.net/u010081710/article/details/77879129
參考位址:https://blog.csdn.net/xiaolyuh123/article/details/80209815
/**
* 手寫重試機制
*/
public class MyJavaRetry {
public static void main(String[] args) throws InterruptedException {
// 重試次數 3 次
int maxRryTimes = 3;
// 時間間隔 3 秒
int intervalTime = 3;
// 重試次數
int redo = 1;
while (redo <= maxRryTimes) {
try {
doBuinessLogic(redo); // 業務處理,可能需要重試的業務
break; //執行成功後直接退出此循環
} catch (Exception e) { //異常時,重試次數增加
redo++;
// 優先使用TimeUnit類中的sleep() 而不是Thread.sleep(4*60*1000);
TimeUnit.SECONDS.sleep(intervalTime);
continue;
}
}
}
private static void doBuinessLogic(int redo) {
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (redo < 3) {
System.err.println("第" + redo + "次執行doBuinessLogic()" + "開始執行時間:" + s.format(new Date()) + "執行失敗");
throw new RuntimeException();
}
System.err.println("第" + redo + "次執行doBuinessLogic()" + "開始執行時間:" + s.format(new Date()) + "執行成功");
}
}
2.Spring Retry 入門
2.1 maven項目pom.xml
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
2.2 SpringRetryDemo
package com.retry;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.Test;
import org.springframework.classify.Classifier;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.retry.RetryPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.backoff.ExponentialRandomBackOffPolicy;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.backoff.NoBackOffPolicy;
import org.springframework.retry.backoff.Sleeper;
import org.springframework.retry.backoff.UniformRandomBackOffPolicy;
import org.springframework.retry.policy.AlwaysRetryPolicy;
import org.springframework.retry.policy.CompositeRetryPolicy;
import org.springframework.retry.policy.ExceptionClassifierRetryPolicy;
import org.springframework.retry.policy.NeverRetryPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.policy.TimeoutRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
/**
* spring-retry 版本 1.2.2
*
* Spring-retry提供了RetryOperations接口的實作類RetryTemplate。
* 通過RetryTemplate來完成重試,下面是使用RetryTemplate重試的一些簡單例子。
*
*/
public class SpringRetryDemo {
private static final int NOTIFY_RETRY_TIMES = 3;
/**
* 簡介:
*
* Spring-retry提供的RetryOperations接口,該接口提供了若幹方法來執行重試操作
*
* public interface RetryOperations {
* <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback) throws E;
*
* <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback, RecoveryCallback<T> recoveryCallback) throws E;
*
* <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback, RetryState retryState) throws E, ExhaustedRetryException;
*
* <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback, RecoveryCallback<T> recoveryCallback, RetryState retryState) throws E;
* }
*
* 調用者通過傳入RetryCallback來完成調用者的重試操作。如果callback執行失敗(抛出某些異常),那麼會按照調用者設定的政策進行重試。
* 重試操作直到成功,或根據使用者設定的條件而退出。
*
* RetryCallback的接口定義如下:
*
* public interface RetryCallback<T, E extends Throwable> {
*
* T doWithRetry(RetryContext context) throws E;
* }
*
*/
/**
* TimeoutRetryPolicy政策(注:不是間隔多長時間進行重試的那個時間)
*
* 代碼定義了TimeoutRetryPolicy政策,TimeoutRetryPolicy逾時時間預設是1秒。
* TimeoutRetryPolicy逾時是指在execute方法内部,從open操作開始到調用
* TimeoutRetryPolicy的canRetry方法這之間所經過的時間。
* 這段時間未超過TimeoutRetryPolicy定義的逾時時間,那麼執行操作,否則抛出異常。
*
* protected <T, E extends Throwable> T doExecute(RetryCallback<T, E> retryCallback,RecoveryCallback<T> recoveryCallback, RetryState state) throws E,ExhaustedRetryException {
* ……略
* RetryContext context = open(retryPolicy, state);
* ……略
* while (canRetry(retryPolicy, context) && !context.isExhaustedOnly())
* // 調用canRetry檢查是否可以重試
* ……略
* }
*
*/
@Test
public void timeoutRetryPolicyTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
// 逾時重試政策
TimeoutRetryPolicy policy = new TimeoutRetryPolicy();
// 逾時時間 預設 1000 毫秒
policy.setTimeout(2000);
// 設定重試政策
template.setRetryPolicy(policy);
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws InterruptedException {
System.out.println("執行Buiness logic");
// TODO 對這個政策模式的了解還是模糊 還為了解逾時到底是哪個地方逾時
// 等待3秒
TimeUnit.SECONDS.sleep(3);
return "SUCCESS";
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
return "failed callback";
}
}
);
System.out.println(result);
}
/**
* SimpleRetryPolicy 政策
*
* will execute the callback at least once, and as many as 3 times.
* 該政策定義了對指定的異常進行若幹次重試。預設情況下,對Exception異常及其子類重試3次.
* 如果建立SimpleRetryPolicy并指定重試異常map,可以選擇性重試或不進行重試.
*
*/
@SuppressWarnings("unused")
@Test
public void simpleRetryPolicyTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
// 簡單重試政策 example one
SimpleRetryPolicy policy1 = new SimpleRetryPolicy();
// 最大重試次數 預設3次 這裡設定為5次
policy1.setMaxAttempts(5);
// 簡單重試政策 example two 1 重試次數5次 2Exception及其子類都進行異重試
// Set the max attempts including the initial attempt before retrying
// and retry on all exceptions (this is the default):
SimpleRetryPolicy policy2 = new SimpleRetryPolicy(5, Collections.singletonMap(Exception.class, true));
// 簡單重試政策 example three
Map<Class<? extends Throwable>, Boolean> retryableExceptionMaps = new HashMap<Class<? extends Throwable>, Boolean>();;
// 空指針異常進行重試 true 進行重試(當Map中的的value為false,那麼執行方法,随後抛出異常不進行重試。)
retryableExceptionMaps.put(NullPointerException.class, true);
SimpleRetryPolicy policy3 = new SimpleRetryPolicy(5, retryableExceptionMaps);
// 設定重試政策
template.setRetryPolicy(policy1);
// template.setRetryPolicy(policy2);
// template.setRetryPolicy(policy3);
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws InterruptedException {
if (true) {
System.out.println("執行Buiness logic. NPE");
// 抛出異常
throw new NullPointerException("NullPointerException");
}
return "SUCCESS";
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
return "failed callback";
}
}
);
System.out.println(result);
}
/**
* NeverRetryPolicy 政策
*
* 執行一次待執行操作,若出現異常後不進行重試。
*
*/
@Test
public void neverRetryPolicyTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
// 從不重試政策
NeverRetryPolicy policy = new NeverRetryPolicy();
// 設定重試政策
template.setRetryPolicy(policy);
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws InterruptedException {
System.out.println("執行Buiness logic. NPE");
// 抛出異常
throw new NullPointerException("NullPointerException");
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
return "failed callback";
}
}
);
System.out.println(result);
}
/**
* AlwaysRetryPolicy 政策
*
* 異常後一直重試直到成功。
*
*/
@Test
public void alwaysRetryPolicyTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
// 一直重試政策
AlwaysRetryPolicy policy = new AlwaysRetryPolicy();
// 設定重試政策
template.setRetryPolicy(policy);
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws InterruptedException {
System.out.println("執行Buiness logic. NPE");
// 抛出異常
throw new NullPointerException("NullPointerException");
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
return "failed callback";
}
}
);
System.out.println(result);
}
/**
* ExceptionClassifierRetryPolicy 政策
*
* 根據産生的異常選擇重試政策。
*
*/
@SuppressWarnings("serial")
@Test
public void exceptionClassifierRetryPolicyTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
/* setPolicyMap 與 setExceptionClassifier 使用一個即可。*/
// 方式 1 setPolicyMap
// 根據異常設定重試政策
ExceptionClassifierRetryPolicy policy1 = new ExceptionClassifierRetryPolicy();
Map<Class<? extends Throwable>, RetryPolicy> policyMap = new HashMap<Class<? extends Throwable>, RetryPolicy>();
// 抛出TimeoutException采用AlwaysRetryPolicy政策
policyMap.put(TimeoutException.class, new AlwaysRetryPolicy());
// 抛出NullPointerException采用NeverRetryPolicy政策
policyMap.put(NullPointerException.class, new NeverRetryPolicy());
// 異常重試政策map
policy1.setPolicyMap(policyMap);
// 方式 2 setExceptionClassifier
// 根據異常設定重試政策
ExceptionClassifierRetryPolicy policy2 = new ExceptionClassifierRetryPolicy();
// 此外可以通過setExceptionClassifier來為異常指定重試政策。
Classifier<Throwable, RetryPolicy> exceptionClassifier = new Classifier<Throwable, RetryPolicy>(){
public RetryPolicy classify(Throwable classifiable) {
if(classifiable instanceof TimeoutException)
return new SimpleRetryPolicy();
return new NeverRetryPolicy();
}
};
policy2.setExceptionClassifier(exceptionClassifier);
// 設定重試政策
template.setRetryPolicy(policy1);
// template.setRetryPolicy(policy2);
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws Exception {
int number = new Random().nextInt(10) + 1;
if (number > 5) {
System.out.println("執行Buiness logic. NPE");
// 抛出異常
throw new NullPointerException("NullPointerException");
} else {
System.out.println("執行Buiness logic. TE");
// 抛出異常
throw new TimeoutException("TimeoutException");
}
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
return "failed callback";
}
}
);
System.out.println(result);
}
/**
* CompositeRetryPolicy 政策
*
* 使用者指定一組政策,随後根據optimistic選項來确認如何重試。
*
* 下面的代碼中建立CompositeRetryPolicy政策,并建立了RetryPolicy數組,
* 數組有兩個具體政策SimpleRetryPolicy與AlwaysRetryPolicy。
*
* optimistic = true
* 當CompositeRetryPolicy設定optimistic為true時,Spring-retry會順序周遊RetryPolicy[]數組,如果有一個重試政策可重試,
* 例如SimpleRetryPolicy沒有達到重試次數,那麼就會進行重試
*
* optimistic = false
* 如果optimistic選項設定為false。那麼有一個重試政策無法重試,那麼就不進行重試。
* 例如SimpleRetryPolicy達到重試次數不能再重試,而AlwaysRetryPolicy可以重試,那麼最終是無法重試的。
*
* 以下代碼,設定setOptimistic(true),而AlwaysRetryPolicy一直可重試,那麼最終可以不斷進行重試。
*
*/
@Test
public void compositeRetryPolicyTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
// 混合政策
CompositeRetryPolicy policy = new CompositeRetryPolicy();
// 政策組
RetryPolicy[] polices = {new SimpleRetryPolicy(), new AlwaysRetryPolicy()};
policy.setPolicies(polices);
policy.setOptimistic(true);
// 設定重試政策
template.setRetryPolicy(policy);
try {
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws Exception {
int number = new Random().nextInt(10) + 1;
if (number > 5) {
System.out.println("執行Buiness logic. NPE");
// 抛出異常
throw new NullPointerException("NullPointerException");
} else {
System.out.println("執行Buiness logic. TE");
// 抛出異常
throw new TimeoutException("TimeoutException");
}
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
return "failed callback";
}
}
);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 退避(BackOff)政策
*
* 當操作執行失敗時,根據設定的重試政策進行重試。通過BackoffPolicy可以設定再次重試的時間間隔。
*
* 接口:
* public interface BackOffPolicy {
* BackOffContext start(RetryContext context);
* void backOff(BackOffContext backOffContext) throws BackOffInterruptedException;
* }
*
* BackOff政策接口的具體實作:
*
* interface BackOffPolicy
* // 實作BackOff接口的抽象類
* abstract StatelessBackOffPolicy
* class FixedBackOffPolicy // 在等待一段固定的時間後,再進行重試。預設為1秒。
* class NoBackOffPolicy // 實作了空方法,是以采用次政策,重試不會等待。這也是RetryTemplate采用的預設退避(backOff)政策
* class UniformRandomBackOffPolicy // 均勻随機退避政策,等待時間為 最小退避時間 + [0,最大退避時間 - 最小退避時間)間的一個随機數,如果最大退避時間等于最小退避時間那麼等待時間為0。
* // 繼承BackOff接口的接口
* interface SleepingBackOffPolicy
* class ExponentialBackOffPolicy // 指數退避政策 ,每次等待時間為 等待時間 = 等待時間 * N ,即每次等待時間為上一次的N倍。如果等待時間超過最大等待時間,那麼以後的等待時間為最大等待時間。
* // 該類是ExponentialBackOffPolicy的子類
* class ExponentialRandomBackOffPolicy // 指數随機政策
* class FixedBackOffPolicy // 與StatelessBackoffPolicy的同名實作類傳回等待時間的方法是一緻的。而兩者的主要差別是,SleepingbackOffPolicy可以設定使用者定義的Sleeper。
* class UniformRandomBackOffPolicy // 與StatelessBackoffPolicy的同名實作類傳回等待時間的方法是一緻的。而兩者的主要差別是,SleepingbackOffPolicy可以設定使用者定義的Sleeper。
*
*/
/**
* 實作BackOff接口的抽象類
* StatelessBackoffPolicy 抽象類下的退避政策
*
*/
@SuppressWarnings("unused")
@Test
public void statelessBackoffPolicyTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
// 簡單重試政策
SimpleRetryPolicy policy = new SimpleRetryPolicy(); // 預設重試3次
// 設定重試政策
template.setRetryPolicy(policy);
// 1. 固定退避政策
FixedBackOffPolicy backOffPolicy1 = new FixedBackOffPolicy();
backOffPolicy1.setBackOffPeriod(2000); // Default back off period - 1000ms.
// 2. 預設退避政策 不等待,直接重試
NoBackOffPolicy backOffPolicy2 = new NoBackOffPolicy();
// 3. 均勻随機退避政策
UniformRandomBackOffPolicy backOffPolicy3 = new UniformRandomBackOffPolicy();
// 等待時間為 最小退避時間 + [0, 最大退避時間 - 最小退避時間)間的一個随機數 (如果最大退避時間等于最小退避時間那麼等待時間為0)
backOffPolicy3.setMinBackOffPeriod(2000); // Default min back off period - 500ms.
backOffPolicy3.setMaxBackOffPeriod(5000); // Default max back off period - 1500ms.
// 設定退避政策
template.setBackOffPolicy(backOffPolicy1);
// template.setBackOffPolicy(backOffPolicy2);
// template.setBackOffPolicy(backOffPolicy3);
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws Exception {
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
int number = new Random().nextInt(10) + 1;
if (number > 5) {
System.out.println("執行Buiness logic. NPE" + "開始執行時間:" + s.format(new Date()));
// 抛出異常
throw new NullPointerException("NullPointerException");
} else {
System.out.println("執行Buiness logic. TE" + "開始執行時間:" + s.format(new Date()));
// 抛出異常
throw new TimeoutException("TimeoutException");
}
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
return "failed callback";
}
}
);
System.out.println(result);
}
/**
* 繼承BackOff接口的接口
* SleepingbackOffPolicy 接口下的退避政策
*
*/
@SuppressWarnings("serial")
@Test
public void sleepingbackOffPolicyTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
// 簡單重試政策
SimpleRetryPolicy policy = new SimpleRetryPolicy();
// 重試5次
policy.setMaxAttempts(5);
// 設定重試政策
template.setRetryPolicy(policy);
// 1. 指數退避政策
ExponentialBackOffPolicy backOffPolicy1 = new ExponentialBackOffPolicy();
// 每次等待時間為 等待時間 = 等待時間 * N ,即每次等待時間為上一次的N倍。 (如果等待時間超過最大等待時間,那麼以後的等待時間為最大等待時間。)
// 以下設定 初始時間間隔為2000毫秒,N = 3,¸最大間隔為6000毫秒,那麼從第3次重試開始,以後每次等待時間都為6000毫秒。
backOffPolicy1.setInitialInterval(2000);// 等待時間 The default 'initialInterval' value - 100 millisecs.
backOffPolicy1.setMultiplier(3);// 等待倍數 The default 'multiplier' value - value 2 (100% increase per backoff).
backOffPolicy1.setMaxInterval(6000);//最大等待時間 The default maximum backoff time (30 seconds).
// 2. 指數随機退避政策
ExponentialRandomBackOffPolicy backOffPolicy2 = new ExponentialRandomBackOffPolicy();
// 算法是 等待時間 = 等待時間 * (1 + Random(随機數) * (N - 1))
backOffPolicy2.setInitialInterval(2000);// 等待時間 The default 'initialInterval' value - 100 millisecs.
backOffPolicy2.setMultiplier(3);// 等待倍數 The default 'multiplier' value - value 2 (100% increase per backoff).
// 3. 固定退避政策
FixedBackOffPolicy backOffPolicy3 = new FixedBackOffPolicy();
backOffPolicy3.setBackOffPeriod(2000); // Default back off period - 1000ms.
// 使用者自定義 sleeper 不知道能幹啥 不懂
Sleeper sleeper3 = new Sleeper() {
@Override
public void sleep(long backOffPeriod) throws InterruptedException {
// 不了解這個的作用
TimeUnit.SECONDS.sleep(10);
System.out.println("sleeper");
}
};
backOffPolicy3.setSleeper(sleeper3);
// 4. 均勻随機退避政策
UniformRandomBackOffPolicy backOffPolicy4 = new UniformRandomBackOffPolicy();
// 等待時間為 最小退避時間 + [0, 最大退避時間 - 最小退避時間)間的一個随機數 (如果最大退避時間等于最小退避時間那麼等待時間為0)
backOffPolicy4.setMinBackOffPeriod(2000); // Default min back off period - 500ms.
backOffPolicy4.setMaxBackOffPeriod(5000); // Default max back off period - 1500ms.
// 使用者自定義 sleeper 不知道能幹啥 不懂
Sleeper sleeper4 = new Sleeper() {
@Override
public void sleep(long backOffPeriod) throws InterruptedException {
// 不了解這個的作用
TimeUnit.SECONDS.sleep(10);
System.out.println("sleeper");
}
};
backOffPolicy4.setSleeper(sleeper4);
// 設定退避政策
template.setBackOffPolicy(backOffPolicy1);
// template.setBackOffPolicy(backOffPolicy2);
// template.setBackOffPolicy(backOffPolicy3);
// template.setBackOffPolicy(backOffPolicy4);
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws Exception {
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
int number = new Random().nextInt(10) + 1;
if (number > 5) {
System.out.println("執行Buiness logic. NPE" + "開始執行時間:" + s.format(new Date()));
// 抛出異常
throw new NullPointerException("NullPointerException");
} else {
System.out.println("執行Buiness logic. TE" + "開始執行時間:" + s.format(new Date()));
// 抛出異常
throw new TimeoutException("TimeoutException");
}
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
return "failed callback";
}
}
);
System.out.println(result);
}
/**
* 監聽器
*
*/
@Test
public void retryListenerTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
// 簡單重試政策
SimpleRetryPolicy policy = new SimpleRetryPolicy(); // 預設重試3次
// 設定重試政策
template.setRetryPolicy(policy);
// 固定時間退避政策
FixedBackOffPolicy backOffPolicy1 = new FixedBackOffPolicy();
backOffPolicy1.setBackOffPeriod(2000); // Default back off period - 1000ms.
// 設定退避政策
template.setBackOffPolicy(backOffPolicy1);
/**
*
* 上述代碼注冊了兩個Listener,Listener中的三個實作方法,onError, open, close會在執行重試操作時被調用,
* 在RetryTemplate中doOpenInterceptors, doCloseInterceptors, doOnErrorInterceptors
* 會調用監聽器對應的open, close, onError 方法。
*
* doOpenInterceptors方法在第一次重試之前會被調用,如果該方法傳回true,則會繼續向下直接,如果傳回false,則抛出異常,停止重試。
*
* doOnErrorInterceptors 在抛出異常後執行,
*
* doCloseInterceptors 會在重試操作執行完畢後調用。
*
*/
// 監聽器1
RetryListener retryListener1 = new RetryListener() {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
System.out.println("1-open");
return true;
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
Throwable throwable) {
System.out.println("1-onError");
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
Throwable throwable) {
System.out.println("1-close");
}
};
// 監聽器1
RetryListener retryListener2 = new RetryListener() {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
System.out.println("2-open");
return true;
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
Throwable throwable) {
System.out.println("2-onError");
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
Throwable throwable) {
System.out.println("2-close");
}
};
// 監聽組
RetryListener[] listeners = {retryListener1, retryListener2};
/*
* 設定監聽器 當注冊多個Listener時,open方法按會按Listener的注冊順序調用,
* 而onError和close則按Listener注冊的順序逆序調用。
*
* open 初始重試調用
* onError 發生異常就調用
* close 重試次數全部結束調用
*/
template.setListeners(listeners);
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws Exception {
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
int number = new Random().nextInt(10) + 1;
if (number > 5) {
System.out.println("執行Buiness logic. NPE" + "開始執行時間:" + s.format(new Date()));
// 抛出異常
throw new NullPointerException("NullPointerException");
} else {
System.out.println("執行Buiness logic. TE" + "開始執行時間:" + s.format(new Date()));
// 抛出異常
throw new TimeoutException("TimeoutException");
}
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
// TODO 推送次數,推送完畢後,還沒有成功,發送預警短信,通知人工處理
return "FAIL";
}
}
);
System.out.println(result);
}
@Test
public void realRetryListenerTest() throws Exception{
// Spring-retry提供了RetryOperations接口的實作類RetryTemplate
RetryTemplate template = new RetryTemplate();
// 簡單重試政策
SimpleRetryPolicy policy = new SimpleRetryPolicy(); // 預設重試3次
// 設定重試政策
template.setRetryPolicy(policy);
// 固定時間退避政策
FixedBackOffPolicy backOffPolicy1 = new FixedBackOffPolicy();
backOffPolicy1.setBackOffPeriod(2000); // Default back off period - 1000ms.
// 設定退避政策
template.setBackOffPolicy(backOffPolicy1);
// 監聽器1
RetryListener retryListener1 = new RetryListener() {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
System.out.println("1-open");
return true;
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
Throwable throwable) {
System.out.println("1-onError");
System.out.println("save FAIL notify info");
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
Throwable throwable) {
if (context.getRetryCount() < NOTIFY_RETRY_TIMES) {
// TODO 表示沒有到達重試次數 就成功了。在這兒入庫,儲存通知成功資訊。
System.out.println("save SUCCESS notify info");
}
System.out.println("1-close" + "重試了" + context.getRetryCount() +"次");
}
};
// 監聽組
RetryListener[] listeners = {retryListener1};
template.setListeners(listeners);
// 執行
String result = template.execute(
new RetryCallback<String, Exception>() {
public String doWithRetry(RetryContext context) throws Exception {
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
int number = new Random().nextInt(10) + 1;
if (number > 5) {
System.out.println("執行Buiness logic. NPE" + "開始執行時間:" + s.format(new Date()));
// 抛出異常
throw new NullPointerException("NullPointerException");
}
return "SUCCESS";
}
},
// 當重試執行完閉,操作還未成為,那麼可以通過RecoveryCallback完成一些失敗事後處理。
new RecoveryCallback<String>() {
public String recover(RetryContext context) throws Exception {
return "FAIL";
}
}
);
System.out.println(result);
}
}
tips:如有疑問,歡迎評論交流。