SpringRetry重試框架的具體使用
spring retry主要實(shí)現(xiàn)了重試和熔斷。
不適合重試的場景:
參數(shù)校驗(yàn)不合法、寫操作等(要考慮寫是否冪等)都不適合重試。
適合重試的場景:
遠(yuǎn)程調(diào)用超時(shí)、網(wǎng)絡(luò)突然中斷等可以重試。
在spring retry中可以指定需要重試的異常類型,并設(shè)置每次重試的間隔以及如果重試失敗是繼續(xù)重試還是熔斷(停止重試)。
一、環(huán)境搭建加入SpringRetry依賴,SpringRetry使用AOP實(shí)現(xiàn),所以也需要加入AOP包
<!-- SpringRetry --><dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId></dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId></dependency>
官方文檔
二、RetryTemplate2.1 RetryTemplate RetryTemplate封裝了Retry基本操作 org.springframework.retry.support.RetryTemplate RetryTemplate中可以指定監(jiān)聽、回退策略、重試策略等 只需要正常new RetryTemplate()即可使用2.2 RetryListenerRetryListener指定了當(dāng)執(zhí)行過程中出現(xiàn)錯(cuò)誤時(shí)的回調(diào)
org.springframework.retry.RetryListener
package org.springframework.retry;public interface RetryListener { /** * 任務(wù)開始執(zhí)行時(shí)調(diào)用,只調(diào)用一次 */ <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback); /** * 任務(wù)執(zhí)行結(jié)束時(shí)(包含重試)調(diào)用,只調(diào)用一次 */ <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable); /** * 出現(xiàn)錯(cuò)誤時(shí)回調(diào) */ <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable);}
配置之后在RetryTemplate中指定
2.3 回退策略2.3.1 FixedBackOffPolicy當(dāng)出現(xiàn)錯(cuò)誤時(shí)延遲多少時(shí)間繼續(xù)調(diào)用
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();fixedBackOffPolicy.setBackOffPeriod(1000L);retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
配置之后在RetryTemplate中指定
2.3.2 ExponentialBackOffPolicy當(dāng)出現(xiàn)錯(cuò)誤時(shí)第一次按照指定延遲時(shí)間延遲后按照指數(shù)進(jìn)行延遲
// 指數(shù)回退(秒),第一次回退1s,第二次回退2s,第三次4秒,第四次8秒ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();exponentialBackOffPolicy.setInitialInterval(1000L);exponentialBackOffPolicy.setMultiplier(2);retryTemplate.setBackOffPolicy(exponentialBackOffPolicy);
配置之后在RetryTemplate中指定
2.4 重試策略重試策略主要指定出現(xiàn)錯(cuò)誤時(shí)重試次數(shù)
// 重試策略SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();retryPolicy.setMaxAttempts(5);retryTemplate.setRetryPolicy(retryPolicy);
配置之后在RetryTemplate中指定
2.5 RetryCallbackRetryCallback為retryTemplate.execute時(shí)執(zhí)行的回調(diào)
public final <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback) throws E
可以使用RetryTemplate完成簡單使用配置retryTemplate
指定回退策略為ExponentialBackOffPolicy 指定重試策略為SimpleRetryPolicy 指定監(jiān)聽器RetryListenerimport com.codecoord.util.PrintUtil;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.retry.RetryCallback;import org.springframework.retry.RetryContext;import org.springframework.retry.RetryListener;import org.springframework.retry.backoff.ExponentialBackOffPolicy;import org.springframework.retry.policy.SimpleRetryPolicy;import org.springframework.retry.support.RetryTemplate;@Configurationpublic class RetryTemplateConfig { /** * 注入retryTemplate */ @Bean public RetryTemplate retryTemplate() {RetryTemplate retryTemplate = new RetryTemplate();/// 回退固定時(shí)間(秒) /* FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();fixedBackOffPolicy.setBackOffPeriod(1000L);retryTemplate.setBackOffPolicy(fixedBackOffPolicy);*/// 指數(shù)回退(秒),第一次回退1s,第二次回退2sExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();exponentialBackOffPolicy.setInitialInterval(1000L);exponentialBackOffPolicy.setMultiplier(2);retryTemplate.setBackOffPolicy(exponentialBackOffPolicy);// 重試策略SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();retryPolicy.setMaxAttempts(5);retryTemplate.setRetryPolicy(retryPolicy);// 設(shè)置監(jiān)聽器,open和close分別在啟動(dòng)和結(jié)束時(shí)執(zhí)行一次RetryListener[] listeners = {new RetryListener() { @Override public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {PrintUtil.print('open');return true; } @Override public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {PrintUtil.print('close'); } @Override public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {PrintUtil.print('onError'); }}};retryTemplate.setListeners(listeners);return retryTemplate; }}
在controller中注入RetryTemplate使用,也可以是在service中
@RestControllerpublic class SpringRetryController { @Resource private RetryTemplate retryTemplate; private static int count = 0; @RequestMapping('/retry') public Object retry() {try { count = 0; retryTemplate.execute((RetryCallback<Void, RuntimeException>) context -> {// 業(yè)務(wù)代碼// ....// 模擬拋出異常++count;throw new RuntimeException('拋出異常'); });} catch (RuntimeException e) { System.out.println('Exception');}return 'retry = ' + count; }}
訪問retry接口,然后觀察日志輸出
18:27:20.648 - http-nio-8888-exec-1 - open18:27:20.649 - http-nio-8888-exec-1 - retryTemplate.execute執(zhí)行18:27:20.649 - http-nio-8888-exec-1 - onError18:27:21.658 - http-nio-8888-exec-1 - retryTemplate.execute執(zhí)行18:27:21.658 - http-nio-8888-exec-1 - onError18:27:23.670 - http-nio-8888-exec-1 - retryTemplate.execute執(zhí)行18:27:23.670 - http-nio-8888-exec-1 - onError18:27:27.679 - http-nio-8888-exec-1 - retryTemplate.execute執(zhí)行18:27:27.679 - http-nio-8888-exec-1 - onError18:27:35.681 - http-nio-8888-exec-1 - retryTemplate.execute執(zhí)行18:27:35.681 - http-nio-8888-exec-1 - onError18:27:35.681 - http-nio-8888-exec-1 - close
三、EnableRetry@EnableRetry開啟重試,在類上指定的時(shí)候方法將默認(rèn)執(zhí)行,重試三次定義service,開啟@EnableRetry注解和指定@Retryable,重試可以參考后面一節(jié)
import org.springframework.retry.annotation.Retryable;public interface RetryService { /** * 重試方法調(diào)用 */ @Retryable void retryServiceCall();}
import org.springframework.retry.annotation.EnableRetry;import org.springframework.stereotype.Service;@EnableRetry@Servicepublic class RetryServiceImpl implements RetryService { @Override public void retryServiceCall() {PrintUtil.print('方法調(diào)用..');throw new RuntimeException('手工異常'); }}
controller中注入service
@RequestMapping('/retryAnnotation')public Object retryAnnotation() { retryService.retryServiceCall(); return 'retryAnnotation';}
將會(huì)默認(rèn)重試
18:46:48.721 - http-nio-8888-exec-1 - 方法調(diào)用..18:46:49.724 - http-nio-8888-exec-1 - 方法調(diào)用..18:46:50.730 - http-nio-8888-exec-1 - 方法調(diào)用..java.lang.RuntimeException: 手工異常
四、Retryable用于需要重試的方法上的注解有以下幾個(gè)屬性
Retryable注解參數(shù)
value:指定發(fā)生的異常進(jìn)行重試 include:和value一樣,默認(rèn)空,當(dāng)exclude也為空時(shí),所有異常都重試 exclude:指定異常不重試,默認(rèn)空,當(dāng)include也為空時(shí),所有異常都重試 maxAttemps:重試次數(shù),默認(rèn)3 backoff:重試補(bǔ)償機(jī)制,默認(rèn)沒有@Backoff 注解 重試補(bǔ)償策略
不設(shè)置參數(shù)時(shí),默認(rèn)使用FixedBackOffPolicy(指定等待時(shí)間),重試等待1000ms 設(shè)置delay,使用FixedBackOffPolicy(指定等待設(shè)置delay和maxDealy時(shí),重試等待在這兩個(gè)值之間均態(tài)分布) 設(shè)置delay、maxDealy、multiplier,使用 ExponentialBackOffPolicy(指數(shù)級重試間隔的實(shí)現(xiàn)),multiplier即指定延遲倍數(shù),比如delay=5000L,multiplier=2,則第一次重試為5秒,第二次為10秒,第三次為20秒@Target({ ElementType.METHOD, ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @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). * If includes is empty but excludes is not, all not excluded exceptions are retried * @return exception types not 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()}. * @date 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. * @date 1.2 */ String exceptionExpression() default ''; /** * Bean names of retry listeners to use instead of default ones defined in Spring context * @return retry listeners bean names */ String[] listeners() default {};}
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @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. * @date 1.2 */ String delayExpression() default ''; /** * 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. Overrides {@link #maxDelay()} * * @return the maximum delay between retries (default 0 = ignored) * @date 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) * @date 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;}
在需要重試的方法上配置對應(yīng)的重試次數(shù)、重試異常的異常類型、設(shè)置回退延遲時(shí)間、重試策略、方法監(jiān)聽名稱
@Componentpublic class PlatformClassService { @Retryable(// 重試異常的異常類型value = {Exception.class},// 最大重試次數(shù)maxAttempts = 5,// 設(shè)置回退延遲時(shí)間backoff = @Backoff(delay = 500),// 配置回調(diào)方法名稱listeners = 'retryListener' ) public void call() {System.out.println('call...');throw new RuntimeException('手工異常'); }}
// 初始延遲2秒,然后之后驗(yàn)收1.5倍延遲重試,總重試次數(shù)4@Retryable(value = {Exception.class}, maxAttempts = 4, backoff = @Backoff(delay = 2000L, multiplier = 1.5))
監(jiān)聽方法,在配置類中進(jìn)行配置
/** * 注解調(diào)用 */@Beanpublic RetryListener retryListener() { return new RetryListener() {@Overridepublic <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { System.out.println('open context = ' + context + ', callback = ' + callback); // 返回true繼續(xù)執(zhí)行后續(xù)調(diào)用 return true;}@Overridepublic <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { System.out.println('close context = ' + context + ', callback = ' + callback);}@Overridepublic <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { System.out.println('onError context = ' + context + ', callback = ' + callback);} };}
調(diào)用服務(wù)
@RestControllerpublic class SpringRetryController { @Resource private PlatformClassService platformClassService;@RequestMapping('/retryPlatformCall') public Object retryPlatformCall() {try { platformClassService.call();} catch (Exception e) { return '嘗試調(diào)用失敗';}return 'retryPlatformCall'; }}
調(diào)用結(jié)果
到此這篇關(guān)于SpringRetry重試框架的具體使用的文章就介紹到這了,更多相關(guān)SpringRetry重試框架內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. 以PHP代碼為實(shí)例詳解RabbitMQ消息隊(duì)列中間件的6種模式2. AJAX實(shí)現(xiàn)文件上傳功能報(bào)錯(cuò)Current request is not a multipart request詳解3. ASP常用日期格式化函數(shù) FormatDate()4. vue-electron中修改表格內(nèi)容并修改樣式5. 微信小程序?qū)崿F(xiàn)商品分類頁過程結(jié)束6. 推薦一個(gè)好看Table表格的css樣式代碼詳解7. 不使用XMLHttpRequest對象實(shí)現(xiàn)Ajax效果的方法小結(jié)8. 基于Surprise協(xié)同過濾實(shí)現(xiàn)短視頻推薦方法示例9. PHP獲取時(shí)間戳等相關(guān)函數(shù)匯總10. ASP新手必備的基礎(chǔ)知識
