推广展示类网站有哪些,管理信息系统,外贸行业网站建设公司排名,王野天女演员葛优照片前言
在日常工作中#xff0c;随着业务日渐庞大#xff0c;不可避免的涉及到调用远程服务#xff0c;但是远程服务的健壮性和网络稳定性都是不可控因素#xff0c;因此#xff0c;我们需要考虑合适的重试机制去处理这些问题#xff0c;最基础的方式就是手动重试#xf…前言
在日常工作中随着业务日渐庞大不可避免的涉及到调用远程服务但是远程服务的健壮性和网络稳定性都是不可控因素因此我们需要考虑合适的重试机制去处理这些问题最基础的方式就是手动重试侵入业务代码去处理再高端一点的通过切面去处理较为优雅的实现重试下面介绍两个重试框架只需要配置好重启策略及重试任务即可使用。
重试任务
这里只是模拟传参、相应及异常具体任务需对应业务
package com.example.test.MessageRetry;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.remoting.RemoteAccessException;Slf4j
public class RetryTask {/*** 重试方法* param param* return*/public static boolean retryTask(String param){log.info(请求参数{},param);int i RandomUtils.nextInt(0,15);log.info(随机数{},i);if(i 0){log.error(参数异常);throw new IllegalArgumentException(参数异常);}else if(i 10){log.error(访问异常);throw new RemoteAccessException(访问异常);}else if(i % 2 0){log.info(成功);return true;}else{log.info(失败);return false;}}
}
Spring-Retry
简介
Spirng-Retry是Spring提供的一个重试框架为spring程序提供声明式重试支持主要针对可能抛出异常的调用操作进行有策略的重试。可以通过代码方式和注解方式实现主要由重试执行者和两个策略构成
RetryTemplet重试执行者可以设置重试策略设置重试上线、如何重试和回退策略立即重试还是等待一段时间后重试默认立即重试如果需要配置等待一段时间后重试则需要指定回退策略通过Execute提交执行操作只有在调用时抛出指定配置的异常才会执行重试重试策略
策略方式NeverRetryPolicy只允许调用RetryCallback一次不允许重试AlwaysRetryPolicy允许无限重试直到成功此方式逻辑不当会导致死循环SimpleRetryPolicy固定次数重试策略默认重试最大次数为3次RetryTemplate默认使用的策略TimeoutRetryPolicy超时时间重试策略默认超时时间为1秒在指定的超时时间内允许重试ExceptionClassifierRetryPolicy设置不同异常的重试策略类似组合重试策略区别在于这里只区分不同异常的重试CircuitBreakerRetryPolicy有熔断功能的重试策略需设置3个参数openTimeout、resetTimeout和delegateCompositeRetryPolicy组合重试策略有两种组合方式乐观组合重试策略是指只要有一个策略允许即可以重试悲观组合重试策略是指只要有一个策略不允许即可以重试但不管哪种组合方式组合中的每一个策略都会执行
重试回退策略
回退策略方式NoBackOffPolicy无退避算法策略每次重试时立即重试FixedBackOffPolicy固定时间的退避策略需设置参数sleeper和backOffPeriodsleeper指定等待策略默认是Thread.sleep即线程休眠backOffPeriod指定休眠时间默认1秒UniformRandomBackOffPolicy随机时间退避策略需设置sleeper、minBackOffPeriod和maxBackOffPeriod该策略在minBackOffPeriod,maxBackOffPeriod之间取一个随机休眠时间minBackOffPeriod默认500毫秒maxBackOffPeriod默认1500毫秒ExponentialBackOffPolicy指数退避策略需设置参数sleeper、initialInterval、maxInterval和multiplierinitialInterval指定初始休眠时间默认100毫秒maxInterval指定最大休眠时间默认30秒multiplier指定乘数即下一次休眠时间为当前休眠时间*multiplierExponentialRandomBackOffPolicy随机指数退避策略引入随机乘数可以实现随机乘数回退
此外还需要配置重试时间间隔、最大重试次数以及可重试异常
实现
代码方式
RetryTemplate通过execute提交执行操作需要准备RetryCallback和RecoveryCallback两个类实例前者对应的就是重试回调逻辑实例包装正常的功能操作RecoveryCallback实现的是整个执行操作结束的恢复操作实例只有在调用的时候抛出了异常并且异常是在exceptionMap中配置的异常才会执行重试操作否则就调用到excute方法的第二个执行方法RecoveryCallback中
package com.example.test.MessageRetry;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;Service
Slf4j
public class SpringRetryService {/*** 重试时间间隔ms默认1000ms*/private long retryPeriodTime 5000L;/*** 最大重试次数*/private int maxRetryNum 3;/*** 哪些结果和异常要重试key表示异常类型value表示是否需要重试*/private MapClass? extends Throwable,Boolean retryMap new HashMap();Testpublic void test(){retryMap.put(IllegalArgumentException.class,true);retryMap.put(RemoteAccessException.class,true);//构建重试模板RetryTemplate retryTemplate new RetryTemplate();//设置重试回退操作策略主要设置重试时间间隔FixedBackOffPolicy backOffPolicy new FixedBackOffPolicy();backOffPolicy.setBackOffPeriod(retryPeriodTime);//设置重试策略主要设置重试次数SimpleRetryPolicy retryPolicy new SimpleRetryPolicy(maxRetryNum,retryMap);retryTemplate.setRetryPolicy(retryPolicy);retryTemplate.setBackOffPolicy(backOffPolicy);Boolean execute retryTemplate.execute(//RetryCallbackretryContext - {boolean b RetryTask.retryTask(aaa);log.info(调用结果{},b);return b;},retryContext - {//RecoveryCallbacklog.info(到达最多尝试次数);return false;});log.info(执行结果{},execute);}
}注解方式
上面我们说到Spring-Retry是Spring提供的那么它就支持依赖整合
!--spring-retry--dependencygroupIdorg.springframework.retry/groupIdartifactIdspring-retry/artifactIdversion1.2.2.RELEASE/version/dependencydependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.1/version/dependency然后在启动类上添加开启注解
//表示是否开启重试属性proxyTargetClassboolean类型是否创建基于子类CGLIB的代理而不是标准的基于接口的代理默认false
EnableRetrypackage com.example.test.MessageRetry;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.remoting.RemoteAccessException;Slf4j
public class RetryTask {/*** 重试方法* param param* return*/public static boolean retryTask(String param){log.info(请求参数{},param);int i RandomUtils.nextInt(0,15);log.info(随机数{},i);if(i -1){log.error(参数异常);throw new IllegalArgumentException(参数异常);
// }else if(i 10){
// log.error(访问异常);
// throw new RemoteAccessException(访问异常);
// }else if(i % 2 0){
// log.info(成功);
// return true;}else{log.info(失败);return false;}}
}
/*** 重试调用方法* param param* return* Retryable注解**/Retryable(value {RemoteAccessException.class,IllegalArgumentException.class},maxAttempts 3,backoff Backoff(delay 5000L,multiplier 2))public void call(String param){RetryTask.retryTask(param);}/*** 达到最大重试次数或抛出了没有指定的异常* param e* param param* return*/Recoverpublic void recover(Exception e,String param){log.error(达到最大重试次数);}Testpublic void retry(){springRetryService.call(aaa);}Retryable注解说明
属性说明value指定重试的异常类型默认为空maxAttempts最大尝试次数默认3次include和value一样默认为空当exclude也为空时默认所有异常exclude指定不处理的异常Backoff重试策略
Backoff注解说明设定重试倍数每次重试时间是上次的n倍
属性说明delay重试之间的等待时间(以毫秒为单位)默认0maxDelay重试之间的最大等待时间(以毫秒为单位)默认0multiplier延迟的倍数默认0.0delayExpression重试之间的等待时间表达式默认空maxDelayExpression重试之间的最大等待时间表达式默认空multiplierExpression指定延迟的倍数表达式默认空random随机指定延迟时间默认false Recover注解说明当重试到达指定次数时将要回调的方法 Retryable和Recover修饰的方法要在同一个类中,且被Retryable和Recover标记的方法不能有返回值这样Recover方法才会生效。由于Retryable注解是通过切面实现的因此我们要避免Retryable 注解的方法的调用方和被调用方处于同一个类中因为这样会使Retryable 注解失效。 我们可以看到Spring-Retry只能针对指定异常重试不能根据执行结果返回值重试整体使用也比较死板下面看下更加灵活的Guava-Retry。
Guava-Retry
简介
Guava-Retry是谷歌的Guava库的一个小扩展允许为任意函数调用创建可配置的重试策略我们可以通过构建重试实例RetryBuilder来设置重试源、配置重试次数、重试超时时间、等待时间间隔等实现优雅的重试机制。
主要属性
属性说明attemptTimeLimiter时间限制策略单次任务执行时间限制超时终止stopStrategy停止重试策略waitStrategy等待策略blockStrategy任务阻塞策略即当前任务执行完下次任务执行前做什么仅有线程阻塞threadSleepStrategyretryException重试异常重试策略listeners自定义重试监听器可用于记录日志等
时间限制策略
策略说明NoAttemptTimeLimit对代理方法不添加时间限制默认FixedAttemptTimeLimit对代理方法的尝试添加固定时间限制
重试策略重试异常
策略说明retryIfException抛出 runtime 异常、checked 异常时都会重试但是抛出 error 不会重试retryIfRuntimeException只会在抛 runtime 异常的时候才重试checked 异常和error 都不重试retryIfExceptionOfType允许我们只在发生特定异常的时候才重试比如NullPointerException 和 IllegalStateException 都属于 runtime 异常也包括自定义的errorretryIfResult可以指定你的 Callable 方法在返回值的时候进行重试
停止策略
策略说明StopAfterDelayStrategy设定最长执行时间无论任务执行几次一旦超时任务终止返回RetryExceptionStopAfterAttemptStrategy设定最大尝试次数一旦超过返回重试异常NeverStopStrategy一直轮询直到获取期望结果
等待策略
策略说明ExceptionWaitStrategy异常时长等待如果抛出的是指定异常则从传入的方法中取得等待时间并返回如果异常不匹配则返回等待时间为0LCompositeWaitStrategy复合时长等待在获取等待时间时会获取多种等待策略各自的等待时间然后累加这些等待时间FibonacciWaitStrategy斐波那契等待策略ExponentialWaitStrategy指数等待时长指数增长若设置了最大时间则停止否则到Long.MAX_VALUEIncrementingWaitStrategy递增等待提供一个初始时长和步长随次数叠加RandomWaitStrategy随机等待时长可以提供一个最大和最小时间从范围内随机FixedWaitStrategy固定等待时长
代码
!--guava-retryer--dependencygroupIdcom.github.rholder/groupIdartifactIdguava-retrying/artifactIdversion2.0.0/version/dependencypackage com.example.test.MessageRetry;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.remoting.RemoteAccessException;Slf4j
public class RetryTask {/*** 重试方法* param param* return*/public static boolean retryTask(String param){log.info(请求参数{},param);int i RandomUtils.nextInt(0,15);log.info(随机数{},i);if(i 3){log.error(参数异常);throw new IllegalArgumentException(参数异常);}else if(i 10){log.error(访问异常);throw new RemoteAccessException(访问异常);}else if(i % 2 0){log.info(成功);return true;}else{log.info(失败);return false;}}
}
package com.example.test.MessageRetry;import com.github.rholder.retry.*;
import com.google.common.base.Predicates;
import lombok.extern.slf4j.Slf4j;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;Service
Slf4j
public class GuavaRetryService {public void guavaRetry(){//构建重试实例RetryBuilder可以设置重试源可以配置重试次数、重试超时时间、等待时间间隔RetryerBooleanretryer RetryerBuilder.BooleannewBuilder()//设置异常重试源.retryIfExceptionOfType(RemoteAccessException.class).retryIfExceptionOfType(IllegalArgumentException.class)//设置根据结果重试 res-resfalse Predicates.containsPattern(_error$).retryIfResult(Predicates.equalTo(false))//设置等待时间.withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))//设置最大重试次数.withStopStrategy(StopStrategies.stopAfterAttempt(3))//设置重试监听可用作重试时的额外动作.withRetryListener(new RetryListener() {Overridepublic V void onRetry(AttemptV attempt) {log.error(第【{}】次调用失败,attempt.getAttemptNumber());}})//设置阻塞策略.withBlockStrategy(BlockStrategies.threadSleepStrategy())//设置时间限制.withAttemptTimeLimiter(AttemptTimeLimiters.noTimeLimit()).build();try{retryer.call(()-RetryTask.retryTask(aaa));}catch (Exception e){e.printStackTrace();}}
}可以看到我们设置了重试三次超过这个限制没有执行成功抛出了重试异常而且也可以根据我们的返回结果来判断。
总结
Spring-Retry和Guava-Retry都是线程安全的重试框架能够保证并发业务下重试逻辑的正确性。两者都很好的将正常方法和重试方法进行了解耦可以设置超时时间、重试次数、间隔时间、监听结果等相比来说Guava-Retry比Spring-Retry更加灵活并且可以通过返回值来进行重试两者都是非常好的重试框架具体的选用看相关的业务场景即可。