写点什么

SpringBoot 技术实践 -SpringRetry 重试框架

  • 2021 年 11 月 11 日
  • 本文字数:5096 字

    阅读完需:约 17 分钟

// 重试策略


SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();


retryPolicy.setMaxAttempts(5);


retryTemplate.setRetryPolicy(retryPolicy);


// 设置监听器,open 和 close 分别在启动和结束时执行一次


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;


}


}


  1. 在 controller 中注入 RetryTemplate 使用,也可以是在 service 中


@RestController


public 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 -> {


// 业务代码


// ....


// 模拟抛出异常


++count;


throw new RuntimeException("抛出异常");


});


} catch (RuntimeException e) {


System.out.println("Exception");


}


return "retry = " + count;


}


}


  1. 访问 retry 接口,然后观察日志输出


18:27:20.648 - http-nio-8888-exec-1 - open


18:27:20.649 - http-nio-8888-exec-1 - retryTemplate.execute 执行


18:27:20.649 - http-nio-8888-exec-1 - onError


18:27:21.658 - http-nio-8888-exec-1 - retryTemplate.execute 执行


18:27:21.658 - http-nio-8888-exec-1 - onError


18:27:23.670 - http-nio-8888-exec-1 - retryTemplate.execute 执行


18:27:23.670 - http-nio-8888-exec-1 - onError


18:27:27.679 - http-nio-8888-exec-1 - retryTemplate.execute 执行


18:27:27.679 - http-nio-8888-exec-1 - onError


18:27:35.681 - http-nio-8888-exec-1 - retryTemplate.execute 执行


18:27:35.681 - http-nio-8888-exec-1 - onError


18:27:35.681 - http-nio-8888-exec-1 - close


三、EnableRetry


================================================================================


  1. @EnableRetry 开启重试,在类上指定的时候方法将默认执行,重试三次

  2. 定义 service,开启 @EnableRetry 注解和指定 @Retryable,重试可以参考后面一节


import org.springframework.retry.annotation.Retryable;


public interface RetryService {


/**


  • 重试方法调用


*/


@Retryable


void retryServiceCall();


}


import org.springframework.retry.annotation.EnableRetry;


import org.springframework.stereotype.Service;


@EnableRetry


@Service


public class RetryServiceImpl implements RetryService {


@Override


public void retryServiceCall() {


PrintUtil.print("方法调用..");


throw new RuntimeException("手工异常");


}


}


  1. controller 中注入 service


@RequestMapping("/retryAnnotation")


public Object retryAnnotation() {


retryService.retryServiceCall();


return "retryAnnotation";


}


  1. 将会默认重试


18:46:48.721 - http-nio-8888-exec-1 - 方法调用..


18:46:49.724 - http-nio-8888-exec-1 - 方法调用..


18:46:50.730 - http-nio-8888-exec-1 - 方法调用..


java.lang.RuntimeException: 手工异常


四、Retryable


==============================================================================


  1. 用于需要重试的方法上的注解

  2. 有以下几个属性


  • Retryable 注解参数

  • value:指定发生的异常进行重试

  • include:和 value 一样,默认空,当 exclude 也为空时,所有异常都重试

  • exclude:指定异常不重试,默认空,当 include 也为空时,所有异常都重试

  • maxAttemps:重试次数,默认 3

  • backoff:重试补偿机制,默认没有

  • @Backoff 注解 重试补偿策略

  • 不设置参数时,默认使用 FixedBackOffPolicy(指定等待时间),重试等待 1000ms

  • 设置 delay,使用 FixedBackOffPolicy(指定等待设置 delay 和 maxDealy 时,重试等待在这两个值之间均态分布)

  • 设置 delay、maxDealy、multiplier,使用 ExponentialBackOffPolicy(指数级重试间隔的实现),multiplier 即指定延迟倍数,比如 delay=5000L,multiplier=2,则第一次重试为 5 秒,第二次为 10 秒,第三次为 20 秒


@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).

  • 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 {};


}


  1. 在需要重试的方法上配置对应的重试次数、重试异常的异常类型、设置回退延迟时间、重试策略、方法监听名称


@Target(ElementType.TYPE)


@Retention(RetentionPolicy.RUNTIME)


@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 de


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


lay 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;


}


@Component


public class PlatformClassService {


@Retryable(


// 重试异常的异常类型


value = {Exception.class},


// 最大重试次数


maxAttempts = 5,


// 设置回退延迟时间


backoff = @Backoff(delay = 500),


// 配置回调方法名称


listeners = "retryListener"


)


public void call() {


System.out.println("call...");


throw new RuntimeException("手工异常");


}


}


// 初始延迟 2 秒,然后之后验收 1.5 倍延迟重试,总重试次数 4


@Retryable(value = {Exception.class}, maxAttempts = 4, backoff = @Backoff(delay = 2000L, multiplier = 1.5))


  1. 监听方法,在配置类中进行配置


/**


  • 注解调用


*/


@Bean


public RetryListener retryListener() {


return new RetryListener() {


@Override


public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {


System.out.println("open context = " + context + ", callback = " + callback);


// 返回 true 继续执行后续调用


return true;


}


@Override


public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,


Throwable throwable) {


System.out.println("close context = " + context + ", callback = " + callback);


}


@Override


public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,


Throwable throwable) {


System.out.println("onError context = " + context + ", callback = " + callback);


}


};


}


  1. 调用服务


@RestController


public class SpringRetryController {


@Resource


private PlatformClassService platformClassService;


@RequestMapping("/retryPlatformCall")

评论

发布
暂无评论
SpringBoot技术实践-SpringRetry重试框架