在开发中,重试是一个经常使用的手段。比如MQ发送消息失败,会采取重试手段,比如工程中使用RPC请求外部服务,可能因为网络波动出现超时而采取重试手段......可以看见重试操作是非常常见的一种处理问题,系统设计的手段。

在普通的开发中,我们用while条件也能达到重试,但开发量大,代码不好维护,容易出现死循环等,今天来试一下spring retry这个专门的重试框架.先来个简单介绍

然后我们快速开始:

1.先引入jar

<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>

2.定义一个service

package com.lpc.myboot.service.impl;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

@EnableRetry
@Service
public class RetryService {

private static final Logger logger = LoggerFactory.getLogger(RetryService.class);

@Retryable(value= {Exception.class},maxAttempts = 3, backoff = @Backoff(delay = 2000l,multiplier = 1))
public void call() throws Exception {
System.out.println(new Date()+"do something...");
try {
int a=1/0;
}catch (Exception e) {
throw new Exception("异常!");
}
}

@Recover
public void recover(Exception e) {
System.out.println("方法调用失败兜底进入兜底操作!");
logger.info(e.getMessage());
}
}

其中@EnableRetry表示能否重试,

@Retryable表示重试的方法,

include 指定处理的异常类。默认为空, 当exclude也为空时,所有异常都重试 
exclude指定不需要处理的异常。默认为空 ,当include也为空时,所有异常都重试 
vaue指定要重试的异常。默认为空 
maxAttempts 最大重试次数。默认3次 
backoff 重试等待策略。默认使用@Backoff注解

@Backoff:重试回退策略(立即重试还是等待一会再重试)
不设置参数时,默认使用FixedBackOffPolicy,重试等待1000ms
只设置delay()属性时,使用FixedBackOffPolicy,重试等待指定的毫秒数
当设置delay()和maxDealy()属性时,重试等待在这两个值之间均态分布
使用delay(),maxDealy()和multiplier()属性时,使用ExponentialBackOffPolicy
当设置multiplier()属性不等于0时,同时也设置了random()属性时,使用ExponentialRandomBackOffPolicy

multiplier:指定延迟的倍数,比如delay=5000l,multiplier=2时,第一次重试为5秒后,第二次为10秒,第三次为20秒

@Recover: 用于方法。用于@Retryable失败时的“兜底”处理方法。 @Recover注释的方法必须要与@Retryable注解的方法“签名”保持一致,第一入参为要重试的异常,其他参数与@Retryable保持一致,返回值也要一样,否则无法执行

@CircuitBreaker:用于方法,实现熔断模式。

include 指定处理的异常类。默认为空
exclude指定不需要处理的异常。默认为空
vaue指定要重试的异常。默认为空
maxAttempts 最大重试次数。默认3次
openTimeout 配置熔断器打开的超时时间,默认5s,当超过openTimeout之后熔断器电路变成半打开状态(只要有一次重试成功,则闭合电路)
resetTimeout 配置熔断器重新闭合的超时时间,默认20s,超过这个时间断路器关闭

此注解解释参考:https://blog.csdn.net/u011116672/article/details/77823867?utm_source=copy

此时代码逻辑就完成了,是不是很简单,我们来运行下看看

可以看到2S执行一次操作,最后进入了失败兜底操作,是可以按照配置重试的,我们来说说几个问题

1.重试的方法必须有异常抛出去,并且抛出去的异常与value中定义的一样;

2. @Recover标注的方法必须是void,不能有返回值

3.重试的service必须在其它service或者controller里才能调用,在本service方法中是不能被调用的,调用了也不会产生重试的效果,

下图是2种调用效果,因此重试的方法必须单独写成一个service;

至此就完成了,我们再来看看普通开发中是怎么用的

public class Test1 {
public static Boolean vpmsRetryCoupon(final String userId) {
// 构建重试模板实例
RetryTemplate retryTemplate = new RetryTemplate();
// 设置重试策略,主要设置重试次数
SimpleRetryPolicy policy = new SimpleRetryPolicy(10, Collections.<Class<? extends Throwable>, Boolean>singletonMap(Exception.class, true));
// 设置重试回退操作策略,主要设置重试间隔时间
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); fixedBackOffPolicy.setBackOffPeriod(100);
retryTemplate.setRetryPolicy(policy); retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
// 通过RetryCallback 重试回调实例包装正常逻辑逻辑,第一次执行和重试执行执行的都是这段逻辑
final RetryCallback<Object, Exception> retryCallback = new RetryCallback<Object, Exception>() {
//RetryContext 重试操作上下文约定,统一spring-try包装
public Object doWithRetry(RetryContext context) throws Exception {
boolean result = pushCouponByVpmsaa(userId);
if (!result) {
throw new RuntimeException();
//这个点特别注意,重试的根源通过Exception返回
} return true;
}
};
// 通过RecoveryCallback 重试流程正常结束或者达到重试上限后的退出恢复操作实例
final RecoveryCallback<Object> recoveryCallback = new RecoveryCallback<Object>() {
public Object recover(RetryContext context) throws Exception {
// logger.info("正在重试发券::::::::::::"+userId);
return null;
}
};
try {
// 由retryTemplate 执行execute方法开始逻辑执行
retryTemplate.execute(retryCallback, recoveryCallback);
} catch (Exception e) {
// logger.info("发券错误异常========"+e.getMessage());
e.printStackTrace();
}
return true;
}

public static void main(String[] args) {
vpmsRetryCoupon("43333");
}

public static Boolean pushCouponByVpmsaa(String userId) {
Random random = new Random();
int a = random.nextInt(10);
System.out.println("a是" + a);
if (a == 8) {
return true;
}else {
return false;
}
}
}

这样用起来非常繁琐,所以我们一般都用注解的方式来实现

参考文章:

https://blog.csdn.net/songhaifengshuaige/article/details/79441326 原理解析

https://www.cnblogs.com/EasonJim/p/7684649.html

https://blog.csdn.net/u012731081/article/details/78892897  原理解析

https://blog.csdn.net/u011116672/article/details/77823867

Spring retry实践的更多相关文章

  1. 异常重试框架Spring Retry实践

    前期准备在Maven项目中添加Spring Retry和切面的依赖 POM: <!-- Spring Retry --> <dependency> <groupId> ...

  2. Spring Retry 在SpringBoot 中的应用

    Spring Boot中使用Spring-Retry重试框架 Spring Retry提供了自动重新调用失败的操作的功能.这在错误可能是暂时的(例如瞬时网络故障)的情况下很有用. 从2.2.0版本开始 ...

  3. 自己动手实践 spring retry 重试框架

    前序 马上过年了,预祝大家,新年快乐,少写bug 什么是spring retry? spring retry是从spring batch独立出来的一个能功能,主要实现了重试和熔断. 什么时候用? 远程 ...

  4. Spring retry基本使用

    Spring retry基本使用 背景介绍 在实际工作过程中,重试是一个经常使用的手段.比如MQ发送消息失败,会采取重试手段,比如工程中使用RPC请求外部服务,可能因为网络 波动出现超时而采取重试手段 ...

  5. Spring+MyBatis实践—MyBatis数据库访问

    关于spring整合mybatis的工程配置,已经在Spring+MyBatis实践—工程配置中全部详细列出.在此,记录一下几种通过MyBatis访问数据库的方式. 通过sqlSessionTempl ...

  6. Spring MVC 实践 - Component

    Spring MVC 实践 标签 : Java与Web Converter Spring MVC的数据绑定并非没有任何限制, 有案例表明: Spring在如何正确绑定数据方面是杂乱无章的. 比如: S ...

  7. Spring MVC 实践 - Base

    Spring MVC 实践 标签 : Java与Web Spring Web MVC Spring-Web-MVC是一种基于请求驱动的轻量级Web-MVC设计模式框架, Spring MVC使用MVC ...

  8. Spring Retry

    最近组内准备将项目中原有的重试功能抽取出来重构为一个重试平台,由于对重试的功能要求比较高,采用了不少中间件和框架(jimdb,jproxy, Elastic-Job ,JMQ,Hbase, Disru ...

  9. Spring Boot实践——Spring AOP实现之动态代理

    Spring AOP 介绍 AOP的介绍可以查看 Spring Boot实践——AOP实现 与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改 ...

随机推荐

  1. 7.Java关键字和保留字

    一.概念 Java关键字(Key Word):  对Java的编译器有特殊的意义,他们用来表示一种数据类型或者表示程序的结构. 保留字(Reserve Word):即它们在Java现有版本中没有特殊含 ...

  2. Python初学者第十三天 三级菜单程序小作业

    13day 作业题目: 三级菜单 作业需求: 数据结构: menu = { '北京':{ '海淀':{ '五道口':{ 'soho':{}, '网易':{}, 'google':{} }, '中关村' ...

  3. 第八次作业——windows各种基本应用的命令处理方法

  4. 延期年金(deferred annuity)

    含义:推迟m个时期后才开始付款的年金. 延期年金现值为 二.永续年金(Perpetuity) 永续年金:无限期支付下去的年金. 为期末付永续年金(perpetuity-immediate)的现值 表示 ...

  5. Mysql进阶-day2

    Mysql cmake方式安装 1.卸载原有mysql下载MySQL安装包 [root@localhost ~]# yum remove mysql* -y [root@localhost ~]# m ...

  6. 企业办公领域: Windows + Office的组合在未来能抵挡住 Google Apps的冲击么

    从个人角度讲,我基本上不怎么喜欢微软的产品,即便是其无处不见的Windows. Windows 8用了几个月的后,实在无法忍受其某些SB的设计,还是换回Win7.另外自从用上了MacBook 以后, ...

  7. codeforces 497E Subsequences Return

    codeforces 497E Subsequences Return 想法 做完这题,学了一些东西. 1.求一个串不同子序列个数的两种方法.解一 解二 2.这道题 \(n\) 很大,很容易想到矩阵加 ...

  8. Mac原生Terminal快速登录ssh

    1. 创建rsa key 在终端中输入以下命令: ssh-keygen -t rsa 完成之后可以在~/.ssh目录下找到公钥和私钥     如果你与我一样有使用gitlab,那么这个秘钥应该已经存在 ...

  9. MongoDB authentication failed

    0.随笔摘要: MongoDB  安装配置 MongoDB  权限控制 MongoDB  注意事项 authentication failed 1.MongoDB  下载安装配置 MongoDB官网  ...

  10. antlr-2.7.6.jar的作用

    项目中没有添加antlr-2.7.6.jar,hibernate不会执行hql语句 并且会报NoClassDefFoundError: antlr/ANTLRException错误