Spring Retry

1. Spring Retry 的工作原理

内部机制

Spring Retry 主要通过 AOP(面向切面编程)实现重试逻辑。以下是 Spring Retry 的内部工作流程:

  1. AOP 拦截器:当一个方法被标记为需要重试,并且该方法抛出了指定类型的异常时,Spring AOP 拦截器会拦截该调用。
  2. 异常捕获:如果该方法抛出指定类型的异常,AOP 拦截器会检查是否符合重试条件。
  3. 重试策略判断:根据配置的 RetryPolicy 和 BackOffPolicy,决定是否进行重试以及重试的时间间隔。
  4. 等待:根据 BackOffPolicy 等待一段时间。
  5. 重试:再次调用目标方法。
  6. 恢复逻辑:如果所有重试都失败,则执行 @Recover 注解定义的恢复逻辑。
RetryTemplate 的工作流程

RetryTemplate 是 Spring Retry 的核心类,它负责管理重试逻辑。以下是它的主要步骤:

  1. 初始化:根据配置初始化 RetryPolicy 和 BackOffPolicy
  2. 方法调用:尝试调用目标方法。
  3. 异常捕获:如果方法抛出异常,检查是否符合重试条件。
  4. 等待:根据 BackOffPolicy 等待一段时间。
  5. 重试:再次调用目标方法。
  6. 恢复:如果所有重试都失败,执行 RecoveryCallback

2. 核心概念的深度解析

RetryPolicy

RetryPolicy 定义了重试策略,决定了在什么情况下应该重试。Spring 提供了几种内置的 RetryPolicy 实现,同时支持自定义实现。

  • SimpleRetryPolicy:基于尝试次数的简单策略。

    SimpleRetryPolicy policy = new SimpleRetryPolicy();
    policy.setMaxAttempts(5); // 设置最大重试次数为5次
  • TimeoutRetryPolicy:基于时间的策略,允许在指定时间内进行重试。

    TimeoutRetryPolicy timeoutPolicy = new TimeoutRetryPolicy();
    timeoutPolicy.setTimeout(5000L); // 设置超时时间为5秒
  • ExceptionClassifierRetryPolicy:根据异常类型决定是否重试。可以通过该策略为不同的异常设置不同的重试策略。

    Map<Class<? extends Throwable>, Boolean> retryableExceptions = new HashMap<>();
    retryableExceptions.put(IllegalArgumentException.class, true);
    retryableExceptions.put(NullPointerException.class, false);ExceptionClassifierRetryPolicy classifier = new ExceptionClassifierRetryPolicy();
    classifier.setPolicyMap(retryableExceptions);
  • CompositeRetryPolicy:组合多个 RetryPolicy,可以定义复杂的重试策略。

BackOffPolicy

BackOffPolicy 控制每次重试之间的等待时间。常见的策略包括:

  • FixedBackOffPolicy:固定延迟时间。

    FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
    backOffPolicy.setBackOffPeriod(2000L); // 设置每次重试之间的延迟时间为2秒
  • ExponentialBackOffPolicy:指数增长的延迟时间。

    ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
    exponentialBackOffPolicy.setInitialInterval(1000L); // 初始延迟时间1秒
    exponentialBackOffPolicy.setMultiplier(2.0); // 每次重试延迟时间乘以2
    exponentialBackOffPolicy.setMaxInterval(10000L); // 最大延迟时间10秒
  • NoBackOffPolicy:无延迟,立即重试。

  • UniformRandomBackOffPolicy:随机延迟时间,但有上下限。

RecoveryCallback

当所有重试都失败后执行的回调函数。用于处理最终失败的情况。

@Recover
public void recover(RuntimeException e) {System.out.println("All retries failed due to: " + e.getMessage());
}

3. 配置方式

注解方式
主配置类

首先,在主配置类中启用重试功能:

import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.EnableRetry;@Configuration
@EnableRetry // 启用Spring Retry功能
public class AppConfig {
}
服务层实现

然后,在需要重试的方法上添加 @Retryable 注解,并且可以定义恢复逻辑:

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;@Service
public class MyService {/*** 使用@Retryable注解的方法,允许在遇到特定异常时进行重试。*/@Retryable(value = {RuntimeException.class}, // 当发生RuntimeException异常时进行重试maxAttempts = 4, // 设置最大重试次数为4次backoff = @Backoff(delay = 2000) // 设置每次重试之间的延迟时间为2秒)public void serviceMethod() throws Exception {System.out.println("Attempting to execute service method...");throw new RuntimeException("Service failure"); // 模拟服务失败}/*** 定义恢复逻辑,当所有重试都失败后执行。*/@Recover // 定义恢复逻辑,当所有重试都失败后执行public void recover(RuntimeException e) {System.out.println("All retries failed due to: " + e.getMessage());}
}
Java 配置类方式

通过 Java 配置类的方式可以手动配置重试模板和拦截器:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;@Configuration
public class RetryConfig {@Beanpublic RetryTemplate retryTemplate() {RetryTemplate retryTemplate = new RetryTemplate();SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();retryPolicy.setMaxAttempts(4); // 设置最大重试次数为4次retryTemplate.setRetryPolicy(retryPolicy);ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();backOffPolicy.setInitialInterval(2000L); // 初始延迟时间2秒retryTemplate.setBackOffPolicy(backOffPolicy);return retryTemplate;}
}

4. 高级用法

自定义 RetryPolicy 和 BackOffPolicy

你可以创建自定义的 RetryPolicyBackOffPolicy,以满足特定需求。例如,创建一个基于业务逻辑的重试策略:

import org.springframework.retry.RetryPolicy;
import org.springframework.retry.RetryContext;public class CustomRetryPolicy implements RetryPolicy {private int attempts = 0;private final int maxAttempts = 3;@Overridepublic boolean canRetry(RetryContext context) {attempts++;return attempts <= maxAttempts;}@Overridepublic void close(RetryContext context) {// 清理资源}@Overridepublic void registerThrowable(RetryContext context, Throwable throwable) {// 处理抛出的异常}
}
异常分类器

可以使用 ExceptionClassifierRetryPolicy 来根据不同的异常类型应用不同的重试策略:

import org.springframework.retry.policy.ExceptionClassifierRetryPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.policy.TimeoutRetryPolicy;@Bean
public RetryTemplate customRetryTemplate() {ExceptionClassifierRetryPolicy classifier = new ExceptionClassifierRetryPolicy();Map<Class<? extends Throwable>, RetryPolicy> policyMap = new HashMap<>();policyMap.put(IllegalArgumentException.class, new SimpleRetryPolicy(3));policyMap.put(NullPointerException.class, new TimeoutRetryPolicy());classifier.setPolicyMap(policyMap);RetryTemplate template = new RetryTemplate();template.setRetryPolicy(classifier);return template;
}
使用 RetryTemplate 手动控制重试

除了使用注解外,你还可以手动使用 RetryTemplate 来控制重试逻辑:

@Autowired
private RetryTemplate retryTemplate;public void performOperation() {retryTemplate.execute(context -> {try {// 执行业务逻辑return null;} catch (Exception e) {throw new RuntimeException(e);}});
}

5. 常见问题及解决方案

1. 重试不生效

确保已经正确启用了 @EnableRetry 注解,并且你的方法上有 @Retryable 注解。同时检查异常类型是否匹配。

2. 事务回滚问题

如果你在重试过程中使用了事务,确保事务能够正确回滚。可以使用 @Transactional 注解来管理事务。

import org.springframework.transaction.annotation.Transactional;@Service
public class MyService {@Transactional@Retryable(value = {RuntimeException.class},maxAttempts = 4,backoff = @Backoff(delay = 2000))public void serviceMethod() throws Exception {// 业务逻辑}
}
3. 性能瓶颈

过多的重试可能导致性能瓶颈。确保只在必要的情况下使用重试,并合理设置重试次数和延迟时间。

示例代码详解

示例1:结合 Spring Boot 和 Spring Retry

以下是一个完整的 Spring Boot 应用示例,展示了如何结合 Spring Retry 来处理临时性故障:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;@SpringBootApplication
@EnableRetry // 启用Spring Retry功能
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}@Service
public class MyService {@Retryable(value = {RuntimeException.class},maxAttempts = 4,backoff = @Backoff(delay = 2000))public void serviceMethod() throws Exception {System.out.println("Attempting to execute service method...");throw new RuntimeException("Service failure");}@Recoverpublic void recover(RuntimeException e) {System.out.println("All retries failed due to: " + e.getMessage());}
}
示例2:自定义重试策略

以下是一个自定义重试策略的示例:

import org.springframework.retry.RetryPolicy;
import org.springframework.retry.RetryContext;public class CustomRetryPolicy implements RetryPolicy {private int attempts = 0;private final int maxAttempts = 3;@Overridepublic boolean canRetry(RetryContext context) {attempts++;return attempts <= maxAttempts;}@Overridepublic void close(RetryContext context) {// 清理资源}@Overridepublic void registerThrowable(RetryContext context, Throwable throwable) {// 处理抛出的异常}
}

6. 最佳实践与注意事项

选择合适的异常类型

只对那些预期可能会暂时失败的操作进行重试,例如网络请求失败、远程服务不可用等情况。避免对非幂等操作进行重试,以免产生副作用。

设置合理的最大尝试次数和延迟
  • maxAttempts:设定最大尝试次数,避免无限重试导致系统资源耗尽。
  • delay:设定重试间隔时间,防止过快重试对系统造成额外压力。
事务管理

如果操作涉及到数据库事务,需注意重试机制如何与事务交互。通常,Spring Retry 不会自动回滚事务,因此你可能需要手动处理事务回滚。

幂等性

确保重试的方法是幂等的,即多次执行同样的操作不会产生副作用或错误结果。这对于涉及数据修改的操作尤为重要。

异常传播

如果所有重试都失败了,最后一个异常会被传播给调用者。可以通过 @Recover 注解定义恢复逻辑。

性能考虑

考虑到重试机制带来的性能开销,确保只在必要的地方使用重试,并合理配置重试策略。

日志记录

在重试逻辑中加入适当的日志记录,有助于调试和监控系统的运行状态。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34579.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker入门篇

使用docker可以很快部署相同的环境,这也是最快的环境构建,接下来就主要对docker中的基础内容进行讲解.Docker 是一个用于开发、交付和运行应用程序的开源平台&#xff0c;它可以让开发者将应用程序及其依赖打包到一个容器中&#xff0c;然后在任何环境中运行这个容器&#xff0…

Learning vtkjs之ContourLoopExtraction

过滤器 等高线轮廓提取 介绍 这个过滤器可以获取一个cut的相交的循环的线&#xff0c;目前这个案例cut是一个平面&#xff0c;应该是可以支持更多隐式公式 效果 可以设置这个平面的原点Origin 法线方向Normal&#xff0c;然后就可以求交了 核心代码 需要实现这个代码主要…

如何高效解决 Java 内存泄漏问题方法论

目录 一、系统化的诊断与优化方法论 二、获取内存快照&#xff1a;内存泄漏的第一步 &#xff08;一&#xff09;自动生成 Heap Dump &#xff08;二&#xff09;手动生成 Heap Dump 三、导入分析工具&#xff1a;MAT 和 JProfiler &#xff08;一&#xff09;MAT (Memor…

新手村:数据预处理-异常值检测方法

机器学习中异常值检测方法 一、前置条件 知识领域要求编程基础Python基础&#xff08;变量、循环、函数&#xff09;、Jupyter Notebook或PyCharm使用。统计学基础理解均值、中位数、标准差、四分位数、正态分布、Z-score等概念。机器学习基础熟悉监督/无监督学习、分类、聚类…

大模型-提示词调优

什么是提示词 提示词&#xff08;Prompt&#xff09;在大模型应用中扮演着关键角色&#xff0c;它是用户输入给模型的一段文本指令 。简单来说&#xff0c;就是我们向大模型提出问题、请求或描述任务时所使用的文字内容。例如&#xff0c;当我们想让模型写一篇关于春天的散文&a…

VS2022输入 scanf 报错解决方法

1.第一种解决办法&#xff08;不推荐&#xff09; •将 scanf 替换为 scanf_s •scanf_s 是VS提供的一个函数&#xff0c;scanf_s函数的使用和scanf是有区别的 •scanf_s 是VS提供的一个函数&#xff0c;其他的编译器可能不认识这个函数&#xff0c;那么我们所写的代码就存在跨…

鸿蒙开发-一多开发之媒体查询功能

在HarmonyOS中&#xff0c;使用ArkTS语法实现响应式布局的媒体查询是一个强大的功能&#xff0c;它允许开发者根据不同的设备特征&#xff08;如屏幕尺寸、屏幕方向等&#xff09;动态地调整UI布局和样式。以下是一个使用媒体查询实现响应式布局的实例&#xff1a; 1. 导入必要…

火语言RPA--列表项内容获取

【组件功能】&#xff1a;获取列表中某项数据内容 配置预览 配置说明 获取 获取数据方式 首项&#xff1a;列表第一条数据 末项&#xff1a;列表最后一条数据 随机项&#xff1a;随机获取列表中一条数据 指定索引项&#xff1a;根据索引获取列表对象中数据。 索引项目位置 …

基于Python+Flask+MySQL+HTML的爬取豆瓣电影top-250数据并进行可视化的数据可视化平台

FlaskMySQLHTML 项目采用前后端分离技术&#xff0c;包含完整的前端&#xff0c;以flask作为后端 Pyecharts、jieba进行前端图表展示 通过MySQL收集格列数据 通过Pyecharts制作数据图表 这是博主b站发布的详细讲解&#xff0c;感兴趣的可以去观看&#xff1a;【Python爬虫可…

解锁MySQL 8.0.14源码调试:Mac 11.6+CLion 2024.3.4实战指南

文章目录 解锁MySQL 8.0.41源码调试&#xff1a;Mac 11.6CLion 2024.3.4实战指南前期准备环境搭建详细步骤安装 CLion安装 CMake 3.30.5准备 MySQL 8.0.14 源码配置 CMake 选项构建 MySQL 项目 调试环境配置与验证配置 LLDB 调试器启动调试验证调试环境 总结与拓展 解锁MySQL 8…

81.HarmonyOS NEXT 状态管理与响应式编程:@Observed深度解析

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; HarmonyOS NEXT 状态管理与响应式编程&#xff1a;Observed深度解析 文章目录 HarmonyOS NEXT 状态管理与响应式编程&#xff1a;Observed深度解析…

【快速入门】MyBatis

一.基础操作 1.准备工作 1&#xff09;引入依赖 一个是mysql驱动包&#xff0c;一个是mybatis的依赖包&#xff1a; <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><vers…

RabbitMQ可靠性进制

文章目录 1.生产者可靠性生产者重连生产者确认小结 2. MQ的可靠性数据持久化LazyQueue小结 3. 消费者的可靠性消费者确认机制消费者失败处理方案业务幂等性唯一消息ID业务判断 兜底方案业务判断 兜底方案 1.生产者可靠性 生产者重连 在某些场景下由于网络波动&#xff0c;可能…

【专项测试】限流测试

简介 限流的目的是防止恶意请求、恶意攻击&#xff0c;或者防止流量超出系统峰值时保护系统免受灭顶之灾。 限流的具体做法是是通过对并发访问/请求进行限速或者对一个时间窗口的请求进行限速在保护系统&#xff0c;一旦达到限制速率则可以拒绝服务&#xff08;定向到错误页&a…

Qt-D指针与Q指针的设计哲学

文章目录 前言PIMLP与二进制兼容性D指针Q指针优化d指针继承Q_D和Q_Q 前言 在探索Qt源码的过程中会看到类的成员有一个d指针&#xff0c;d指针类型是一个private的类&#xff0c;这种设计模式称为PIMPL&#xff08;pointer to implementation&#xff09;&#xff0c;本文根据Q…

ctf web入门知识合集

文章目录 01做题思路02信息泄露及利用robots.txt.git文件泄露dirsearch ctfshow做题记录信息搜集web1web2web3web4web5web6web7web8SVN泄露与 Git泄露的区别web9web10 php的基础概念php的基础语法1. PHP 基本语法结构2. PHP 变量3.输出数据4.数组5.超全局变量6.文件操作 php的命…

LangChain 工作流编排

文章目录 LCEL流式调用案例invoke的异步调用异步流中的事件 LCEL LangChain Expression Language&#xff0c;是一种强大的工作流编排工具&#xff0c;可以从基本组件构建复杂的任务链&#xff08;Chain&#xff09;&#xff0c;有如下亮点&#xff1a; 流式支持&#xff1b;…

PyTorch 深度学习实战(14):Deep Deterministic Policy Gradient (DDPG) 算法

在上一篇文章中&#xff0c;我们介绍了 Proximal Policy Optimization (PPO) 算法&#xff0c;并使用它解决了 CartPole 问题。本文将深入探讨 Deep Deterministic Policy Gradient (DDPG) 算法&#xff0c;这是一种用于连续动作空间的强化学习算法。我们将使用 PyTorch 实现 D…

3.14-1列表

列表 一.列表的介绍和定义 1 .列表 类型: <class list> 2.符号:[] 3.定义列表: 方式1:[] 通过[] 来定义 list[1,2,3,4,6] print(type(list)) #<class list> 方式2: 通过list 转换 str2"12345" print(type(str2)) #<class str> list2lis…

Java集合 - HashMap

HashMap 是 Java 集合框架中的一个重要类&#xff0c;位于 java.util 包中。它实现了 Map 接口&#xff0c;基于哈希表的数据结构来存储键值对&#xff08;key-value pairs&#xff09;。HashMap 允许使用 null 作为键和值&#xff0c;并且是非同步的&#xff08;非线程安全的&…