Spring框架中一个有用的小组件:Spring Retry
1、概述
Spring Retry 是Spring框架中的一个组件,
它提供了自动重新调用失败操作的能力。这在错误可能是暂时发生的(如瞬时网络故障)的情况下很有帮助。
在本文中,我们将看到使用Spring Retry的各种方式:注解、RetryTemplate以及回调。
2、Maven依赖
让我们首先将spring-retry依赖项添加到我们的pom.xml文件中:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
我们还需要将Spring AOP添加到我们的项目中:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
可以查看Maven Central来获取最新版本的spring-retry
和spring-aspects 依赖项。
3、开启Spring Retry
要在应用程序中启用Spring Retry,我们需要将@EnableRetry注释添加到我们的@Configuration类:
@Configuration
@EnableRetry
public class AppConfig { ... }
4、使用Spring Retry
4.1、@Retryable而不用恢复
我们可以使用@Retryable注解为方法添加重试功能:
@Service
public interface MyService {
@Retryable(value = RuntimeException.class)
void retryService(String sql);
}
在这里,当抛出RuntimeException时尝试重试。
根据@Retryable的默认行为,重试最多可能发生3次,重试之间有1秒的延迟。
4.2、@Retryable和@Recover
现在让我们使用@Recover注解添加一个恢复方法:
@Service
public interface MyService {
@Retryable(value = SQLException.class)
void retryServiceWithRecovery(String sql) throws SQLException;
@Recover
void recover(SQLException e, String sql);
}
这里,当抛出SQLException时重试会尝试运行。 当@Retryable方法因指定异常而失败时,@Recover注解定义了一个单独的恢复方法。
因此,如果retryServiceWithRecovery方法在三次尝试之后还是抛出了SQLException,那么recover()方法将被调用。
恢复处理程序的第一个参数应该是Throwable类型(可选)和相同的返回类型。其余的参数按相同顺序从失败方法的参数列表中填充。
4.3、自定义@Retryable的行为
为了自定义重试的行为,我们可以使用参数maxAttempts和backoff:
@Service
public interface MyService {
@Retryable( value = SQLException.class,
maxAttempts = 2, backoff = @Backoff(delay = 100))
void retryServiceWithCustomization(String sql) throws SQLException;
}
这样最多将有两次尝试和100毫秒的延迟。
4.4、使用Spring Properties
我们还可以在@Retryable注解中使用properties。
为了演示这一点,我们将看到如何将delay和maxAttempts的值外部化到一个properties文件中。
首先,让我们在名为retryConfig.properties的文件中定义属性:
retry.maxAttempts=2
retry.maxDelay=100
然后我们指示@Configuration类加载这个文件:
@PropertySource("classpath:retryConfig.properties")
public class AppConfig { ... }
// ...
最后,我们可以在@Retryable的定义中注入retry.maxAttempts和retry.maxDelay的值:
@Service
public interface MyService {
@Retryable( value = SQLException.class, maxAttemptsExpression = "${retry.maxAttempts}",
backoff = @Backoff(delayExpression = "${retry.maxDelay}"))
void retryServiceWithExternalizedConfiguration(String sql) throws SQLException;
}
请注意,我们现在使用的是maxAttemptsExpression和delayExpression而不是maxAttempts和delay。
5、RetryTemplate
5.1、RetryOperations
Spring Retry提供了RetryOperations接口,它提供了一组execute()方法:
public interface RetryOperations {
<T> T execute(RetryCallback<T> retryCallback) throws Exception;
...
}
execute()方法的参数RetryCallback,是一个接口,可以插入需要在失败时重试的业务逻辑:
public interface RetryCallback<T> {
T doWithRetry(RetryContext context) throws Throwable;
}
5.2、RetryTemplate配置
RetryTemplate是RetryOperations的一个实现。
让我们在@Configuration类中配置一个RetryTemplate的bean:
@Configuration
public class AppConfig {
//...
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(2000l);
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(2);
retryTemplate.setRetryPolicy(retryPolicy);
return retryTemplate;
}
}
这个RetryPolicy确定了何时应该重试操作。
其中SimpleRetryPolicy定义了重试的固定次数,另一方面,BackOffPolicy用于控制重试尝试之间的回退。
最后,FixedBackOffPolicy会使重试在继续之前暂停一段固定的时间。
5.3、使用RetryTemplate
要使用重试处理来运行代码,我们可以调用retryTemplate.execute()方法:
retryTemplate.execute(new RetryCallback<Void, RuntimeException>() {
@Override
public Void doWithRetry(RetryContext arg0) {
myService.templateRetryService();
...
}
});
我们可以使用lambda表达式代替匿名类:
retryTemplate.execute(arg0 -> {
myService.templateRetryService();
return null;
});
6、监听器
监听器在重试时提供另外的回调。我们可以用这些来关注跨不同重试的各个横切点。
6.1、添加回调
回调在RetryListener接口中提供:
public class DefaultListenerSupport extends RetryListenerSupport {
@Override
public <T, E extends Throwable> void close(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
logger.info("onClose");
...
super.close(context, callback, throwable);
}
@Override
public <T, E extends Throwable> void onError(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
logger.info("onError");
...
super.onError(context, callback, throwable);
}
@Override
public <T, E extends Throwable> boolean open(RetryContext context,
RetryCallback<T, E> callback) {
logger.info("onOpen");
...
return super.open(context, callback);
}
}
open和close的回调在整个重试之前和之后执行,而onError应用于单个RetryCallback调用。
6.2、注册监听器
接下来,我们将我们的监听器(DefaultListenerSupport)注册到我们的RetryTemplate bean:
@Configuration
public class AppConfig {
...
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
...
retryTemplate.registerListener(new DefaultListenerSupport());
return retryTemplate;
}
}
7、测试结果
为了完成我们的示例,让我们验证一下结果:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes = AppConfig.class,
loader = AnnotationConfigContextLoader.class)
public class SpringRetryIntegrationTest {
@Autowired
private MyService myService;
@Autowired
private RetryTemplate retryTemplate;
@Test(expected = RuntimeException.class)
public void givenTemplateRetryService_whenCallWithException_thenRetry() {
retryTemplate.execute(arg0 -> {
myService.templateRetryService();
return null;
});
}
}
从测试日志中可以看出,我们已经正确配置了RetryTemplate和RetryListener:
2020-01-09 20:04:10 [main] INFO c.p.s.DefaultListenerSupport - onOpen
2020-01-09 20:04:10 [main] INFO c.pinmost.springretry.MyServiceImpl - throw RuntimeException in method templateRetryService()
2020-01-09 20:04:10 [main] INFO c.p.s.DefaultListenerSupport - onError
2020-01-09 20:04:12 [main] INFO c.pinmost.springretry.MyServiceImpl - throw RuntimeException in method templateRetryService()
2020-01-09 20:04:12 [main] INFO c.p.s.DefaultListenerSupport - onError
2020-01-09 20:04:12 [main] INFO c.p.s.DefaultListenerSupport - onClose
8、结论
在本文中,我们看到了如何使用注解、RetryTemplate和回调监听器来使用Spring Retry。
原文地址:https://www.baeldung.com/spring-retry
翻译:码农熊猫
更多技术干货,请访问我的个人网站https://pinmost.com,或关注公众号【码农熊猫】
Spring框架中一个有用的小组件:Spring Retry的更多相关文章
- spring框架中一个跟String的trim方法一样的方法
@Test public void testTrimWhitespace() throws Exception { assertEquals(null, StringUtils.trimWhitesp ...
- 细说shiro之五:在spring框架中集成shiro
官网:https://shiro.apache.org/ 1. 下载在Maven项目中的依赖配置如下: <!-- shiro配置 --> <dependency> <gr ...
- Spring5源码解析-Spring框架中的单例和原型bean
Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...
- Spring框架中IoC(控制反转)的原理(转)
原文链接:Spring框架中IoC(控制反转)的原理 一.IoC的基础知识以及原理: 1.IoC理论的背景:在采用面向对象方法设计的软件系统中,底层实现都是由N个对象组成的,所有的对象通过彼此的合作, ...
- 漫谈 GOF 设计模式在 Spring 框架中的实现
原文地址:梁桂钊的博客 博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」.一群同频者,一起成长,一起精进,打破认知的局限性. 漫谈 GOF 设计模式在 Spring ...
- 设计模式在 Spring 框架中的良好应用
在开始正文之前,请你先思考几个问题: 你项目中有使用哪些 GOF 设计模式 说一说 GOF 23 种设计模式的设计理念 说说 Spring 框架中如何实现设计模式 假设我是面试官问起了你这些面试题,你 ...
- 再析在spring框架中解决多数据源的问题
在前面我写了<如何在spring框架中解决多数据源的问题>,通过设计模式中的Decorator模式在spring框架中解决多数据源的问题,得到了许多网友的关注.在与网友探讨该问题的过程中, ...
- Spring框架中 配置c3p0连接池 完成对数据库的访问
开发准备: 1.导入jar包: ioc基本jar jdbcTemplate基本jar c3p0基本jar 别忘了mysql数据库驱动jar 原始程序代码:不使用配置文件方式(IOC)生成访问数据库对象 ...
- Spring框架中ModelAndView、Model、ModelMap区别
原文地址:http://www.cnblogs.com/google4y/p/3421017.html SPRING框架中ModelAndView.Model.ModelMap区别 注意:如果方法 ...
随机推荐
- Deformable 可变形的DETR
Deformable 可变形的DETR This repository is an official implementation of the paper Deformable DETR: Defo ...
- Paddle Inference原生推理库
Paddle Inference原生推理库 深度学习一般分为训练和推理两个部分,训练是神经网络"学习"的过程,主要关注如何搜索和求解模型参数,发现训练数据中的规律,生成模型.有了训 ...
- 3D车道线检测:Gen-LaneNet
3D车道线检测:Gen-LaneNet Gen-LaneNet: A Generalized and Scalable Approach for 3D Lane Detection 论文链接:http ...
- 适用于Windows和Linux的Yolo-v3和Yolo-v2(下)
适用于Windows和Linux的Yolo-v3和Yolo-v2(下) 如何训练(检测自定义对象): (培养老YOLO V2 yolov2-voc.cfg,yolov2-tiny-voc.cfg,yo ...
- GVS灵动系列家族上新 | 稳住,我们能“银”
用天赐的色库 给生活增加些艺术的气息 生活本应多点探索的乐趣 今天 GVS灵动系列家族流光银(白玻璃) 全新上线 用灵感朝圣自然之道 邂逅另一种柔性美学 与早前的经典黑.星耀灰 和而不同,美美与共 携 ...
- .Net RabbitMQ实战指南——进阶(一)
备份交换器 备份交换器,英文名称为Alternate Exchange,简称AE.通过在声明交换器(调用channel.ExchangeDeclare方法)时添加alternate-exchange参 ...
- docker基本底层原理
docker是怎么工作的 Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socket客户端进行访问 DockerServer接收到DockerClie ...
- [UWP] WinUI 2.6 使用指南
2021年6月24日,Windows 11 正式对外发布,对于UWP开发者来说,这一天同样值得纪念,因为WinUI 2.6也正式发布了! 相同的时间点意味着一件事,即WinUI 2.6和Windows ...
- 使用Azure WebJob的一点心得
Azure WebApp Service 是非常适合中小型项目的云服务. 从我实际使用的感受来看, 有如下几个优点: 1 部署方便, 可以从VS一键发布 2 缩放方便, scale in / scal ...
- CentOS7日志管理工具 journalctl
1.简介 日志管理工具journalctl是centos7上专有的日志管理工具,该工具是从message这个文件里读取信息. Systemd统一管理所有Unit的启动日志.带来的好处就是,可以只用jo ...