SpringBoot 技术实践 -SpringRetry 重试框架,贼厉害
}
配置之后在 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, E extends Throwable> T execute(RetryCallback<T, E> retryCallback) throws E
[](
)2.6 核心使用
可以使用 RetryTemplate 完成简单使用
配置 retryTemplate
指定回退策略为 ExponentialBackOffPolicy
指定重试策略为 SimpleRetryPolicy
指定监听器 RetryListener
i
mport 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 <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 中
@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;
}
}
访问 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:
<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
*/
评论