优雅处理失败:深入了解 Spring Retry

优雅处理失败:深入了解 Spring Retry

在分布式系统中,处理失败和异常是不可避免的任务。Spring Retry 是 Spring 生态系统中一个强大的库,它提供了一种优雅的机制来处理失败的操作,通过重试来增加系统的鲁棒性。本文将深入介绍 Spring Retry 的核心概念、用法以及如何在 Spring Boot 中应用它。

1. 为什么需要重试?

在分布式系统中,服务之间的调用、数据库操作、远程服务请求等可能面临各种故障,例如网络超时、服务不可用等。重试机制能够有效地应对这些瞬时性的故障,提高系统的可用性。

Spring Retry 提供了一种声明式的方式,允许开发者定义重试策略,并集成到业务逻辑中,从而减少样板代码,使代码更加清晰和可维护。

2. Spring Retry 核心概念

2.1 RetryTemplate

RetryTemplate 是 Spring Retry 的核心类之一。它定义了一个重试操作的模板,包括了重试策略、重试间隔、重试次数等。通常,我们使用 RetryTemplateexecute 方法来执行需要重试的业务逻辑。

RetryTemplate retryTemplate = new RetryTemplate();

retryTemplate.execute(context -> {
    // 重试的业务逻辑
    // ...
    return result;
});

2.2 RetryPolicy

RetryPolicy 定义了重试的策略。Spring Retry 提供了一些内置的实现,如 SimpleRetryPolicyExponentialBackOffPolicy 等。开发者也可以根据自己的需求实现自定义的 RetryPolicy

RetryPolicy retryPolicy = new SimpleRetryPolicy(3);

上述示例中,SimpleRetryPolicy 表示最多重试 3 次。

2.3 BackOffPolicy

BackOffPolicy 定义了在重试操作之间的等待时间。Spring Retry 也提供了一些内置的实现,如 FixedBackOffPolicyExponentialBackOffPolicy

BackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();

2.4 RetryListener

RetryListener 允许我们在重试的不同阶段注册监听器,以执行一些自定义的逻辑。例如,在重试开始、重试成功、重试失败等时机执行特定的操作。

RetryListener retryListener = new MyRetryListener();

3. 在 Spring Boot 中使用 Spring Retry

Spring Boot 对 Spring Retry 进行了集成,使用它变得更加简单。以下是在 Spring Boot 项目中使用 Spring Retry 的基本步骤:

3.1 引入依赖

pom.xml 文件中添加 Spring Retry 依赖:

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starterartifactId>
dependency>

3.2 使用RetryTemplate

import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryPolicy;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
public class Test {
    public static void main(String[] args) {
        // 创建一个retry模板
        RetryTemplate retryTemplate = new RetryTemplate();
        // 重试的次数
        RetryPolicy retryPolicy = new SimpleRetryPolicy(3);
        // 重试的时间间隔
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(1000); // 1秒

        retryTemplate.setRetryPolicy(retryPolicy);
        retryTemplate.setBackOffPolicy(backOffPolicy);

        // 执行重试的逻辑,并返回结果
        String result = retryTemplate.execute(new RetryCallback<String, RuntimeException>() {
            @Override
            public String doWithRetry(RetryContext context) throws RuntimeException {
                System.out.println("执行业务逻辑");

                if (Math.random() < 0.8) {
                    throw new MySpringRetryException("异常");
                }

                return "success";
            }
        });
    }
}

优雅处理失败:深入了解 Spring Retry_第1张图片

3.2 在方法上添加 @Retryable 注解并自定义监听器、动态传参

使用注解
@Slf4j
@Service
public class TestService {
    
    @Retryable(value = MySpringRetryException.class,maxAttempts = 3,backoff =@Backoff(delay = 1000),listeners = {"myRetryListener"})
    public void springRetryMethod(){
        log.info("请求SpringRetryMethod");
        LogTestModel logTestModel = new LogTestModel();
        logTestModel.setOrderId("XXXX20231212001");
        logTestModel.setUserName("ADMIN");
        // 动态传参到MyRetryListener中获取
        RetryContext context = RetrySynchronizationManager.getContext();
        context.setAttribute("logTestModel",logTestModel);
        throw new MySpringRetryException("重试一下");
    }
}
定义监听器
@Slf4j
@Component
public class MyRetryListener extends RetryListenerSupport {
    @Override
    public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        LogTestModel logTestModel = (LogTestModel) context.getAttribute("logTestModel");
        
        log.info("Retry 出现问题了:" + throwable.getMessage());
        log.info("Retry logTestModel.userName:" + logTestModel.getUserName());
        log.info("Retry logTestModel.orderId" + logTestModel.getOrderId());
    }

    @Override
    public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
        return super.open(context, callback);
    }
    

    // 重试完成的时候调用
    @Override
    public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        log.info("Retry 关闭了");
    }
}
自定义的异常
public class MySpringRetryException extends RuntimeException {
    private static final long serialVersionUID = 1L;
    
    private Integer code;
    
    private String message;
    
    public MySpringRetryException() {
    }

    public MySpringRetryException(String message) {
        this.message = message;
    }

    public MySpringRetryException(String message, Integer code) {
        this.message = message;
        this.code = code;
    }
    
    @Override
    public String getMessage() {
        return message;
    }

    public Integer getCode() {
        return code;
    }

    public MySpringRetryException setMessage(String message) {
        this.message = message;
        return this;
    }
}

在上述示例中,@Retryable 注解标记了一个可能会重试的方法。value 属性指定了需要触发重试的异常类型,maxAttempts 指定了最大重试次数,backoff 指定了重试间隔。

优雅处理失败:深入了解 Spring Retry_第2张图片

3.3 在配置类上添加 @EnableRetry 注解

@Configuration
@EnableRetry
@EnableAspectJAutoProxy
public class AppConfig {
}

通过在启动类上添加 @EnableRetry 注解,开启了 Spring Retry 的支持。

4. 总结

Spring Retry 是一个强大的库,可以轻松处理分布式系统中的失败和异常。通过声明式的方式定义重试策略,减少了样板代码,使得代码更加清晰和可维护。

在使用 Spring Retry 时,需要根据具体的业务场景选择合适的重试策略、重试间隔等参数。合理使用重试机制可以提高系统的可用性和鲁棒性。

启动类上添加 @EnableRetry 注解,开启了 Spring Retry 的支持。

4. 总结

Spring Retry 是一个强大的库,可以轻松处理分布式系统中的失败和异常。通过声明式的方式定义重试策略,减少了样板代码,使得代码更加清晰和可维护。

在使用 Spring Retry 时,需要根据具体的业务场景选择合适的重试策略、重试间隔等参数。合理使用重试机制可以提高系统的可用性和鲁棒性。

你可能感兴趣的:(spring,java,spring,boot)