Spring-Retry的使用詳解
1 Spring-Retry的簡(jiǎn)介
在日常的一些場(chǎng)景中, 很多需要進(jìn)行重試的操作.而spring-retry是spring提供的一個(gè)基于spring的重試框架,非常簡(jiǎn)單好用.
2 Spring中的應(yīng)用
1 導(dǎo)入maven坐標(biāo)
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
2 添加被調(diào)用類(lèi)
@Slf4j
public class RetryDemo {
public static boolean retryMethod(Integer param) {
int i = new Random().nextInt(param);
log.info("隨機(jī)生成的數(shù):{}", i);
if (1 == i) {
log.info("為1,返回true.");
return true;
} else if (i < 1) {
log.info("小于1,拋出參數(shù)異常.");
throw new IllegalArgumentException("參數(shù)異常");
} else if (i > 1 && i < 10) {
log.info("大于1,小于10,拋出參數(shù)異常.");
return false;
} else {
//為其他
log.info("大于10,拋出自定義異常.");
throw new RemoteAccessException("大于10,拋出自定義異常");
}
}
}
3 添加測(cè)試類(lèi)
@Slf4j
public class SpringRetryTest {
/**
* 重試間隔時(shí)間ms,默認(rèn)1000ms
*/
private long fixedPeriodTime = 1000L;
/**
* 最大重試次數(shù),默認(rèn)為3
*/
private int maxRetryTimes = 3;
/**
* 表示哪些異常需要重試
* key一定要為T(mén)hrowable異常的子類(lèi) Class<? extends Throwable>
* value為true表示需要重試
*/
private Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
@Test
public void test() {
// 1 添加異常的處理結(jié)果 true為需要重試 false為不需要重試
exceptionMap.put(RemoteAccessException.class, true);
// 2 構(gòu)建重試模板實(shí)例
RetryTemplate retryTemplate = new RetryTemplate();
// 3 設(shè)置重試回退操作策略 設(shè)置重試間隔時(shí)間
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
// 4 設(shè)置重試策略 設(shè)置重試次數(shù) 設(shè)置異常處理結(jié)果
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
//5 重試模板添加重試策略 添加回退操作策略
retryTemplate.setRetryPolicy(retryPolicy);
retryTemplate.setBackOffPolicy(backOffPolicy);
// 6 調(diào)用方法
Boolean resp = retryTemplate.execute(
// RetryCallback 重試回調(diào)方法
retryContext -> {
boolean result = RetryDemo.retryMethod(110);
log.info("方法返回結(jié)果= {}", result);
return result;
},
// RecoveryCallback 異?;卣{(diào)方法
retryContext -> {
//
log.info("超過(guò)最大重試次數(shù)或者拋出了未定義的異常!!!");
return false;
}
);
log.info("接口返回結(jié)果 = {}",resp);
}
}
/*
// 查看結(jié)果
[main] INFO com.cf.demo.SpringRetry.SpringRetryTest - 超過(guò)最大重試次數(shù)或者拋出了未定義的異常!!!
[main] INFO com.cf.demo.SpringRetry.SpringRetryTest - 接口返回結(jié)果 = false
*/
從代碼的書(shū)寫(xiě)注解可以看到,RetryTemplate對(duì)象是Spring-Retry框架的重試執(zhí)行者, 由它添加重試策略,回退操作策略等(注釋第五步).RetryTemplate執(zhí)行重試方法(注釋第六步),通過(guò)execute方法, 傳入的參數(shù)是重試回調(diào)邏輯對(duì)象RetryCallback 和執(zhí)行操作結(jié)束的恢復(fù)對(duì)象RecoveryCallback. 且可以切換添加的異常種類(lèi), 得知,只有添加過(guò)相應(yīng)的異常,才會(huì)觸發(fā)重試操作,否則直接調(diào)用RecoveryCallback對(duì)象方法.
RetryTemplate的部分源碼:
/**
* Keep executing the callback until it either succeeds or the policy dictates that we
* stop, in which case the recovery callback will be executed.
*
* @see RetryOperations#execute(RetryCallback, RecoveryCallback)
* @param retryCallback the {@link RetryCallback}
* @param recoveryCallback the {@link RecoveryCallback}
* @throws TerminatedRetryException if the retry has been manually terminated by a
* listener.
*/
@Override
public final <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback,
RecoveryCallback<T> recoveryCallback) throws E {
return doExecute(retryCallback, recoveryCallback, null);
}
RetryTemplate添加重試策略源碼:
/**
* Setter for {@link RetryPolicy}.
*
* @param retryPolicy the {@link RetryPolicy}
*/
public void setRetryPolicy(RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
}
RetryPolicy接口的實(shí)現(xiàn)類(lèi):
AlwaysRetryPolicy:允許無(wú)限重試,直到成功,可能會(huì)導(dǎo)致死循環(huán)
CircuitBreakerRetryPolicy:有熔斷功能的重試策略,需設(shè)置3個(gè)參數(shù)openTimeout、resetTimeout和delegate
CompositeRetryPolicy:組合重試策略,有兩種組合方式,樂(lè)觀組合重試策略是指只要有一個(gè)策略允許即可以重試,
悲觀組合重試策略是指只要有一個(gè)策略不允許即可以重試,但不管哪種組合方式,組合中的每一個(gè)策略都會(huì)執(zhí)行
ExceptionClassifierRetryPolicy:設(shè)置不同異常的重試策略,類(lèi)似組合重試策略,區(qū)別在于這里只區(qū)分不同異常的重試
NeverRetryPolicy:只允許調(diào)用RetryCallback一次,不允許重試
SimpleRetryPolicy:固定次數(shù)重試策略,默認(rèn)重試最大次數(shù)為3次,RetryTemplate默認(rèn)使用的策略
TimeoutRetryPolicy:超時(shí)時(shí)間重試策略,默認(rèn)超時(shí)時(shí)間為1秒,在指定的超時(shí)時(shí)間內(nèi)允許重試
RetryTemplate添加回退策略源碼:
/**
* Setter for {@link BackOffPolicy}.
*
* @param backOffPolicy the {@link BackOffPolicy}
*/
public void setBackOffPolicy(BackOffPolicy backOffPolicy) {
this.backOffPolicy = backOffPolicy;
}
BackOffPolicy的實(shí)現(xiàn)類(lèi):
ExponentialBackOffPolicy:指數(shù)退避策略,需設(shè)置參數(shù)sleeper、initialInterval、maxInterval和multiplier,initialInterval指定初始休眠時(shí)間,默認(rèn)100毫秒,maxInterval指定最大休眠時(shí)間,默認(rèn)30秒,multiplier指定乘數(shù),即下一次休眠時(shí)間為當(dāng)前休眠時(shí)間*multiplier
ExponentialRandomBackOffPolicy:隨機(jī)指數(shù)退避策略,引入隨機(jī)乘數(shù)可以實(shí)現(xiàn)隨機(jī)乘數(shù)回退
FixedBackOffPolicy:固定時(shí)間的退避策略,需設(shè)置參數(shù)sleeper和backOffPeriod,sleeper指定等待策略,默認(rèn)是Thread.sleep,即線(xiàn)程休眠,backOffPeriod指定休眠時(shí)間,默認(rèn)1秒
NoBackOffPolicy:無(wú)退避算法策略,每次重試時(shí)立即重試
UniformRandomBackOffPolicy:隨機(jī)時(shí)間退避策略,需設(shè)置sleeper、minBackOffPeriod和maxBackOffPeriod,該策略在[minBackOffPeriod,maxBackOffPeriod之間取一個(gè)隨機(jī)休眠時(shí)間,minBackOffPeriod默認(rèn)500毫秒,maxBackOffPeriod默認(rèn)1500毫秒
3 SpringBoot中的應(yīng)用
1 導(dǎo)入maven坐標(biāo)
<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.1</version>
</dependency>
2 添加一個(gè)管理類(lèi)
@Service
@Slf4j
public class SpringRetryDemo {
/**
* 重試所調(diào)用方法
* @return
*/
// delay=2000L表示延遲2秒 multiplier=2表示兩倍 即第一次重試2秒后,第二次重試4秒后,第三次重試8秒后
@Retryable(value = {RemoteAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 2))
public boolean call(Integer param) {
return RetryDemo.retryMethod(param);
}
/**
* 超過(guò)最大重試次數(shù)或拋出沒(méi)有指定重試的異常
* @param e
* @param param
* @return
*/
@Recover
public boolean recover(Exception e, Integer param) {
log.info("請(qǐng)求參數(shù)為: ", param);
log.info("超過(guò)最大重試次數(shù)或拋出沒(méi)有指定重試的異常, e = {} ", e.getMessage());
return false;
}
}
3 啟動(dòng)類(lèi)上添加注解@EnableRetry
@SpringBootApplication
@EnableRetry
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
4 添加測(cè)試類(lèi)
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
@Slf4j
public class DemoApplicationTests {
@Autowired
private SpringRetryDemo springRetryDemo;
@Test
public void testRetry() {
boolean result = springRetryDemo.call(110);
log.info("方法返回結(jié)果為: {}", result);
}
}
/* 運(yùn)行結(jié)果:
隨機(jī)生成的數(shù):77
大于10,拋出自定義異常.
隨機(jī)生成的數(shù):23
大于10,拋出自定義異常.
隨機(jī)生成的數(shù):82
大于10,拋出自定義異常.
請(qǐng)求參數(shù)為:
超過(guò)最大重試次數(shù)或拋出沒(méi)有指定重試的異常, e = 大于10,拋出自定義異常
方法返回結(jié)果為: false
*/
注解說(shuō)明:
@Enableretry注解,啟用重試功能(默認(rèn)是否基于子類(lèi)代理,默認(rèn)是否, 即是基于Java接口代理)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@Import(RetryConfiguration.class)
@Documented
public @interface EnableRetry {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*
* @return whether to proxy or not to proxy the class
*/
boolean proxyTargetClass() default false;
}
@Retryable注解, 標(biāo)記的方法發(fā)生異常時(shí)會(huì)重試
- value 指定發(fā)生的異常進(jìn)行重試
- include 與value一樣,默認(rèn)為空,當(dāng)exclude同時(shí)為空時(shí),所有異常都重試
- exclude 指定異常不重試,默認(rèn)為空,當(dāng)include同時(shí)為空,所有異常都重試
- maxAttemps 重試次數(shù),默認(rèn)3
- backoff 重試補(bǔ)充機(jī)制 默認(rèn)是@Backoff()注解
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Retryable {
/**
* Retry interceptor bean name to be applied for retryable method. Is mutually
* exclusive with other attributes.
* @return the retry interceptor bean name
*/
String interceptor() default "";
/**
* Exception types that are retryable. Synonym for includes(). Defaults to empty (and
* if excludes is also empty all exceptions are retried).
* @return exception types to retry
*/
Class<? extends Throwable>[] value() default {};
/**
* Exception types that are retryable. Defaults to empty (and if excludes is also
* empty all exceptions are retried).
* @return exception types to retry
*/
Class<? extends Throwable>[] include() default {};
/**
* Exception types that are not retryable. Defaults to empty (and if includes is also
* empty all exceptions are retried).
* @return exception types to retry
*/
Class<? extends Throwable>[] exclude() default {};
/**
* A unique label for statistics reporting. If not provided the caller may choose to
* ignore it, or provide a default.
*
* @return the label for the statistics
*/
String label() default "";
/**
* Flag to say that the retry is stateful: i.e. exceptions are re-thrown, but the
* retry policy is applied with the same policy to subsequent invocations with the
* same arguments. If false then retryable exceptions are not re-thrown.
* @return true if retry is stateful, default false
*/
boolean stateful() default false;
/**
* @return the maximum number of attempts (including the first failure), defaults to 3
*/
int maxAttempts() default 3;
/**
* @return an expression evaluated to the maximum number of attempts (including the first failure), defaults to 3
* Overrides {@link #maxAttempts()}.
* @since 1.2
*/
String maxAttemptsExpression() default "";
/**
* Specify the backoff properties for retrying this operation. The default is a
* simple {@link Backoff} specification with no properties - see it's documentation
* for defaults.
* @return a backoff specification
*/
Backoff backoff() default @Backoff();
/**
* Specify an expression to be evaluated after the {@code SimpleRetryPolicy.canRetry()}
* returns true - can be used to conditionally suppress the retry. Only invoked after
* an exception is thrown. The root object for the evaluation is the last {@code Throwable}.
* Other beans in the context can be referenced.
* For example:
* <pre class=code>
* {@code "message.contains('you can retry this')"}.
* </pre>
* and
* <pre class=code>
* {@code "@someBean.shouldRetry(#root)"}.
* </pre>
* @return the expression.
* @since 1.2
*/
String exceptionExpression() default "";
}
@Backoff注解
- delay 延遲多久后重試
- multiplier 延遲的倍數(shù)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(RetryConfiguration.class)
@Documented
public @interface Backoff {
/**
* Synonym for {@link #delay()}.
*
* @return the delay in milliseconds (default 1000)
*/
long value() default 1000;
/**
* A canonical backoff period. Used as an initial value in the exponential case, and
* as a minimum value in the uniform case.
* @return the initial or canonical backoff period in milliseconds (default 1000)
*/
long delay() default 0;
/**
* The maximimum wait (in milliseconds) between retries. If less than the
* {@link #delay()} then the default of
* {@value org.springframework.retry.backoff.ExponentialBackOffPolicy#DEFAULT_MAX_INTERVAL}
* is applied.
*
* @return the maximum delay between retries (default 0 = ignored)
*/
long maxDelay() default 0;
/**
* If positive, then used as a multiplier for generating the next delay for backoff.
*
* @return a multiplier to use to calculate the next backoff delay (default 0 =
* ignored)
*/
double multiplier() default 0;
/**
* An expression evaluating to the canonical backoff period. Used as an initial value
* in the exponential case, and as a minimum value in the uniform case.
* Overrides {@link #delay()}.
* @return the initial or canonical backoff period in milliseconds.
* @since 1.2
*/
String delayExpression() default "";
/**
<<<<<<< HEAD
* An expression evaluating to the maximum wait (in milliseconds) between retries.
* If less than the {@link #delay()} then ignored.
=======
* An expression evaluating to the maximimum wait (in milliseconds) between retries.
* If less than the {@link #delay()} then the default of
* {@value org.springframework.retry.backoff.ExponentialBackOffPolicy#DEFAULT_MAX_INTERVAL}
* is applied.
>>>>>>> Fix @Backoff JavaDocs - maxDelay
* Overrides {@link #maxDelay()}
*
* @return the maximum delay between retries (default 0 = ignored)
* @since 1.2
*/
String maxDelayExpression() default "";
/**
* Evaluates to a vaule used as a multiplier for generating the next delay for backoff.
* Overrides {@link #multiplier()}.
*
* @return a multiplier expression to use to calculate the next backoff delay (default 0 =
* ignored)
* @since 1.2
*/
String multiplierExpression() default "";
/**
* In the exponential case ({@link #multiplier()} > 0) set this to true to have the
* backoff delays randomized, so that the maximum delay is multiplier times the
* previous delay and the distribution is uniform between the two values.
*
* @return the flag to signal randomization is required (default false)
*/
boolean random() default false;
}
@Recover注解
當(dāng)重試達(dá)到規(guī)定的次數(shù)后,被注解標(biāo)記的方法將被調(diào)用, 可以在此方法中進(jìn)行日志的記錄等操作.(該方法的入?yún)㈩?lèi)型,返回值類(lèi)型需要和重試方法保持一致)
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Import(RetryConfiguration.class)
@Documented
public @interface Recover {
}
參考資料:
https://blog.csdn.net/zzzgd_666/article/details/84377962
到此這篇關(guān)于Spring-Retry的使用詳解的文章就介紹到這了,更多相關(guān)Spring-Retry 使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java中Spring Security的實(shí)例詳解
這篇文章主要介紹了java中Spring Security的實(shí)例詳解的相關(guān)資料,spring security是一個(gè)多方面的安全認(rèn)證框架,提供了基于JavaEE規(guī)范的完整的安全認(rèn)證解決方案,需要的朋友可以參考下2017-09-09
java實(shí)現(xiàn)圖片水平和垂直翻轉(zhuǎn)效果
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)圖片水平和垂直翻轉(zhuǎn)效果,圖片旋轉(zhuǎn)的靈活運(yùn)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
解析rainbond以應(yīng)用為中心的架構(gòu)設(shè)計(jì)原理
這篇文章主要為大家介紹了rainbond以應(yīng)用為中心的架構(gòu)設(shè)計(jì)實(shí)現(xiàn)及原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-02-02
Java利用VLC開(kāi)發(fā)簡(jiǎn)易視屏播放器功能
這篇文章主要介紹了Java利用VLC開(kāi)發(fā)簡(jiǎn)易視屏播放器,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08
java開(kāi)發(fā)_圖片截取工具實(shí)現(xiàn)原理
本文將詳細(xì)介紹java開(kāi)發(fā)_圖片截取工具實(shí)現(xiàn)原理,需要了解的朋友可以參考下2012-11-11
BlockingQueue隊(duì)列處理高并發(fā)下的日志
這篇文章主要介紹了BlockingQueue隊(duì)列處理高并發(fā)下的日志示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
JDBC簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
什么是JDBC?這篇文章就為大家詳細(xì)介紹了Java語(yǔ)言中用來(lái)規(guī)范客戶(hù)端程序如何來(lái)訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的應(yīng)用程序接口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
淺談Java中的final關(guān)鍵字與C#中的const, readonly關(guān)鍵字
下面小編就為大家?guī)?lái)一篇淺談Java中的final關(guān)鍵字與C#中的const, readonly關(guān)鍵字。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10

