[Java]RetryTemplate重试机制工具

2022 年 4 月 27 日 星期三(已编辑)
/ ,
7
这篇文章上次修改于 2024 年 4 月 11 日 星期四,可能部分内容已经不适用,如有疑问可询问作者。

[Java]RetryTemplate重试机制工具

基于 RetryTemplate,封装为工具包使用

  1. RetryUtils

package com.common.utils;

import com.common.enums.RetryTypeEnum;
import lombok.SneakyThrows;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryState;
import org.springframework.retry.backoff.BackOffPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.backoff.ExponentialRandomBackOffPolicy;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

/**
 * @Author: jinyiming
 * @Date: 2022/4/27
 **/
public final class RetryUtils {

    private RetryUtils() {
    }

    /**
     * 重试最大等待时间
     */
    private static final long MAX_RETRY_TIME = 60 * 1000L;


    /**
     * 使用策略进行重试
     *
     * @param retryCount    重试次数
     * @param typeEnum      {@link RetryTypeEnum}    重试类型
     * @param millisecond   重试间隔时间
     * @param retryCallback {@link RetryCallback}    需要重试的内容
     * @param <T>           回调返回的对象类型
     * @param <E>           它声明的异常类型可以被抛出
     * @return T重试值
     */
    public static <T, E extends Throwable> T retry(Integer retryCount, RetryTypeEnum typeEnum, long millisecond, RetryCallback<T, E> retryCallback) {
        return retryCore(retryCount, typeEnum, millisecond, retryCallback, null, null);
    }

    /**
     * 使用策略进行重试
     *
     * @param retryCount       重试次数
     * @param typeEnum         {@link RetryTypeEnum}    重试类型
     * @param millisecond      重试间隔时间
     * @param retryCallback    {@link RetryCallback}    需要重试的内容
     * @param recoveryCallback {@link RecoveryCallback}    重试完成之后还失败需要执行的内容
     * @param <T>              回调返回的对象类型
     * @param <E>              它声明的异常类型可以被抛出
     * @return T重试值
     */
    public static <T, E extends Throwable> T retry(Integer retryCount, RetryTypeEnum typeEnum, long millisecond, RetryCallback<T, E> retryCallback,
                                                   RecoveryCallback<T> recoveryCallback) {
        return retryCore(retryCount, typeEnum, millisecond, retryCallback, recoveryCallback, null);
    }

    /**
     * 使用策略进行重试
     *
     * @param retryCount    重试次数
     * @param typeEnum      {@link RetryTypeEnum}    重试类型
     * @param millisecond   重试间隔时间
     * @param retryCallback {@link RetryCallback}    需要重试的内容
     * @param state         {@link RetryState}    重试状态
     * @param <T>           回调返回的对象类型
     * @param <E>           它声明的异常类型可以被抛出
     * @return T重试值
     */
    public static <T, E extends Throwable> T retry(Integer retryCount, RetryTypeEnum typeEnum, long millisecond, RetryCallback<T, E> retryCallback,
                                                   RetryState state) {
        return retryCore(retryCount, typeEnum, millisecond, retryCallback, null, state);
    }

    /**
     * 使用策略进行重试
     *
     * @param retryCount       重试次数
     * @param typeEnum         {@link RetryTypeEnum}    重试类型
     * @param millisecond      重试间隔时间
     * @param retryCallback    {@link RetryCallback}    需要重试的内容
     * @param recoveryCallback {@link RecoveryCallback}    重试完成之后还失败需要执行的内容
     * @param state            {@link RetryState}    重试状态
     * @param <T>              回调返回的对象类型
     * @param <E>              它声明的异常类型可以被抛出
     * @return T重试值
     */
    public static <T, E extends Throwable> T retry(Integer retryCount, RetryTypeEnum typeEnum, long millisecond, RetryCallback<T, E> retryCallback,
                                                   RecoveryCallback<T> recoveryCallback, RetryState state) {
        return retryCore(retryCount, typeEnum, millisecond, retryCallback, recoveryCallback, state);
    }


    @SneakyThrows
    private static <T, E extends Throwable> T retryCore(Integer retryCount, RetryTypeEnum typeEnum, long millisecond, RetryCallback<T, E> retryCallback,
                                                        RecoveryCallback<T> recoveryCallback, RetryState state) {
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(retryCount > 0 ? retryCount : 3);
        RetryTemplate retryTemplate = new RetryTemplate();
        retryTemplate.setRetryPolicy(retryPolicy);
        BackOffPolicy backOffPolicy;
        switch (typeEnum) {
            case EXPONENTIAL:
                backOffPolicy = new ExponentialRandomBackOffPolicy();
                ((ExponentialRandomBackOffPolicy) backOffPolicy).setInitialInterval(millisecond);
                ((ExponentialRandomBackOffPolicy) backOffPolicy).setMaxInterval(MAX_RETRY_TIME);
                break;
            case RANDOM_EXPONENTIAL:
                backOffPolicy = new ExponentialBackOffPolicy();
                ((ExponentialBackOffPolicy) backOffPolicy).setInitialInterval(millisecond);
                ((ExponentialBackOffPolicy) backOffPolicy).setMaxInterval(MAX_RETRY_TIME);
                break;
            default:
                backOffPolicy = new FixedBackOffPolicy();
                ((FixedBackOffPolicy) backOffPolicy).setBackOffPeriod(millisecond);
                break;
        }
        retryTemplate.setBackOffPolicy(backOffPolicy);
        return retryTemplate.execute(retryCallback, recoveryCallback, state);
    }
}
  1. RetryTypeEnum

package com.bf.form.common.enums;

/**
 * @Author: jinyiming
 * @Date: 2022/4/27
 **/
public enum RetryTypeEnum implements ContentEnum {
    /**
     * 默认
     */
    DEFAULT("默认", 1),
    /**
     * 指数
     */
    EXPONENTIAL("指数", 2),
    /**
     * 随机指数
     */
    RANDOM_EXPONENTIAL("随机指数", 3),
    ;

    private final String content;

    private final Integer value;

    RetryTypeEnum(String content, Integer value) {
        this.content = content;
        this.value = value;
    }

    @Override
    public String getContent() {
        return this.content;
    }

    @Override
    public Integer getValue() {
        return this.value;
    }
}
  1. 使用

BillInfo billInfo = RetryUtils.retry(5, RetryTypeEnum.EXPONENTIAL, 5000, (RetryCallback<BillInfo, Throwable>) context -> {
                if (context.getRetryCount() >= 1) {
                    log.info(String.format("查询异常,正在重试%s次", context.getRetryCount()));
                }
                return billInfoDomain.getById();
            }, context -> {
                log.error(context.getLastThrowable().getMessage(), context.getLastThrowable());
                throw context.getLastThrowable();
            });

4.依赖包


org.springframework.retry
  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...