SpringRetry重试框架的具体使用

网友投稿 234 2022-12-25

SpringRetry重试框架的具体使用

目录一、环境搭建二、RetryTemplate2.1 RetryTemplate2.2 RetryListener2.3 回退策略2.3.1 FixedBackOffPolicy2.3.2 ExponentialBackOffPolicy2.4 重试策略2.5 RetryCallback2.6 核心使用三、EnableRetry四、Retryable

spring retry主要实现了重试和熔断。

不适合重试的场景:

参数校验不合法、写操作等(要考虑写是否幂等)都不适合重试。

适合重试的场景:

远程调用超时、网络突然中断等可以重试。

在spring retry中可以指定需要重试的异常类型,并设置每次重试的间隔以及如果重试失败是继续重试还是熔断(停止重试)。

一、环境搭建

加入SpringRetry依赖,SpringRetry使用AOP实现,所以也需要加入AOP包

org.springframework.retry

spring-retry

org.springframework

spring-aspects

官方文档

二、RetryTemplate

2.1 RetryTemplate

RetryTemplate封装了Retry基本操作

org.springframework.retry.support.RetryTemplate

RetryTemplate中可以指定监听、回退策略、重试策略等

只需要正常new RetryTemplate()即可使用

2.2 RetryListener

RetryListener指定了当执行过程中出现错误时的回调

org.springframework.retry.RetryListener

package org.springframework.retry;

public interface RetryListener {

/**

* 任务开始执行时调用,只调用一次

*/

boolean open(RetryContext context, RetryCallback callback);

/**

* 任务执行结束时(包含重试)调用,只调用一次

*/

void close(RetryContext context, RetryCallback callback, Throwable throwable);

/**

* 出现错误时回调

*/

void onError(RetryContext context, RetryCallback callback, Throwable throwable);

}

配置之后在RetryTemplate中指定

2.3 回退策略

2.3.1 FixedBackOffPolicy

当出现错误时延迟多少时间继续调用

FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();

fixedBackOffPolicy.setBackOffPeriod(1000L);

retryTemplate.setBackOffPolicy(fixedBackOffPolicy);

配置之后在RetryTemplate中指定

2.3.2 ExponentialBackOffPolicy

当出现错误时第一次按照指定延迟时间延迟后按照指数进行延迟

// 指数回退(秒),第一次回退1s,第二次回退2s,第三次4秒,第四次8秒

ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();

exponentialBackOffPolicy.setInitialInterval(1000L);

exponentialBackOffPolicy.setMultiplier(2);

retryTemplate.setBackOffPolicy(exponentialBackOffPolicy);

配置之后在RetryTemplate中指定

2.4 重试策略

重试策略主要指定出现错误时重试次数

// 重试策略

SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();

retryPolicy.setMaxAttempts(5);

retryTemplate.setRetryPolicy(retryPolicy);

配置之后在RetryTemplate中指定

2.5 RetryCallback

RetryCallback为retryTemplate.execute时执行的回调

public final T execute(RetryCallback retryCallback) throws E

2.6 核心使用

可以使用RetryTemplate完成简单使用

配置retryTemplate

指定回退策略为ExponentialBackOffPolicy

指定重试策略为SimpleRetryPolicy

指定监听器RetryListener

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

@Configuration

public class RetryTemplateConfig {

/**

* 注入retryTemplate

*/

@Bean

public RetryTemplate retryTemplate() {

RetryTemplate retryTemplate = new RetryTemplate();

/// 回退固定时间(秒)

/* FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();

fixedBackOffPolicy.setBackOffPeriod(1000L);

retryTemplate.setBackOffPolicy(fixedBackOffPolicy);*/

// 指数回退(秒),第一次回退1s,第二次回退2s

ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();

exponentialBackOffPolicy.setInitialInterval(1000L);

exponentialBackOffPolicy.setMultiplier(2);

retryTemplate.setBackOffPolicy(exponentialBackOffPolicy);

// 重试策略

SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();

retryPolicy.setMaxAttempts(5);

retryTemplate.setRetryPolicy(retryPolicy);

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

RetryListener[] listeners = {

new RetryListener() {

@Override

public boolean open(RetryContext context, RetryCallback callback) {

PrintUtil.print("open");

return true;

}

@Override

public void close(RetryContext context, RetryCallback callback,

Throwable throwable) {

PrintUtil.print("close");

}

@Override

public void onError(RetryContext context, RetryCallback callback,

Throwable throwable) {

PrintUtil.print("onError");

}

}

};

retryTemplate.setListeners(listeners);

return retryTemplate;

}

}

在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) context -> {

// 业务代码

// ....

// 模拟抛出异常

++count;

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

});

} catch (RuntimeException e) {

System.out.println("Exception");

}

return "retry = " + count;

}

}

访问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

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

定义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("手工异常");

}

}

controller中注入service

@RequestMapping("/retryAnnotation")

public Object retryAnnotation() {

retryService.retryServiceCall();

return "retryAnnotation";

}

将会默认重试

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

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

有以下几个属性

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:

*

* {@code "message.contains('you can retry this')"}.

*

* and

*

* {@code "@someBean.shouldRetry(#root)"}.

*

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

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

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

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

/**

* 注解调用

*/

@Bean

public RetryListener retryListener() {

return new RetryListener() {

@Override

public boolean open(RetryContext context, RetryCallback callback) {

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

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

return true;

}

@Override

public void close(RetryContext context, RetryCallback callback,

Throwable throwable) {

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

}

@Override

public void onError(RetryContext context, RetryCallback callback,

Throwable throwable) {

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

}

};

}

调用服务

@RestController

public class SpringRetryController {

@Resource

private PlatformClassService platformClassService;

@RequestMapping("/retryPlatformCall")

public Object retryPlatformCall() {

try {

platformClassService.call();

} catch (Exception e) {

return "尝试调用失败";

}

return "retryPlatformCall";

}

}

调用结果

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringBoot SpringEL表达式的使用
下一篇:Java反应式框架Reactor中的Mono和Flux
相关文章

 发表评论

暂时没有评论,来抢沙发吧~