Spring retry实践

在开发中,重试是一个经常使用的手段。比如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

原文地址:https://www.cnblogs.com/lpcyj/p/9743286.html

时间: 2024-08-03 10:50:27

Spring retry实践的相关文章

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

前序 马上过年了,预祝大家,新年快乐,少写bug 什么是spring retry? spring retry是从spring batch独立出来的一个能功能,主要实现了重试和熔断. 什么时候用? 远程调用超时.网络突然中断可以重试.对于重试是有场景限制的,不是什么场景都适合重试,比如参数校验不合法.写操作等(要考虑写是否幂等)都不适合重试. 怎么用? 1,首先我们新建一个maven工程(如果不会,请移步 http://www.cnblogs.com/JJJ1990/p/8384386.html,

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

关于spring整合mybatis的工程配置,已经在Spring+MyBatis实践—工程配置中全部详细列出.在此,记录一下几种通过MyBatis访问数据库的方式. 通过sqlSessionTemplate来进行数据库访问. 通过Dao接口来进行数据库访问. 使用@Select注解形式访问数据库 1.在spring框架中使用mybatis来进行数据操作配置,参考Spring+MyBatis实践—工程配置的spring-datasources.xml文件. 2.Demo1—通过sqlSession

Spring MVC 实践 - Base

Spring MVC 实践 标签 : Java与Web Spring Web MVC Spring-Web-MVC是一种基于请求驱动的轻量级Web-MVC设计模式框架, Spring MVC使用MVC架构思想, 对Web层进行职责解耦,使用请求-响应模型将数据.业务与视图进行分离, 简化开发. MVC MVC(模型-视图-控制器)是一个以设计界面应用程序为基础的架构模式,通过分离模型-视图-控制器在应用中的角色将业务逻辑从界面中解耦: 模型负责封装应用数据和业务逻辑; 视图仅负责展示数据; 控制

Spring+MyBatis实践—中文乱码

多种中文乱码问题及解决: jsp页面乱码 表单提交乱码 URL中文参数乱码 1.jsp页面乱码解决(2步): 新建jsp页面: <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Trans

Spring+MyBatis实践—登录和权限控制

1.实现用户登录功能: 通过session来实现用户登录功能.在用户登录时,将用户的相关信息放在HttpSession对象用,其中HttpSession对象可以通过HttpServletRequest的getSession方法获得.同时,HttpSession对象对应Jsp内置对象session,在jsp页面中也可以通过session来访问,如通过jstl标签库来访问session中的内容: <c:if test="${sessionScope.username == null}"

Spring+MyBatis实践——登录与权限控制

Spring+MyBatis实践--登录与权限控制 1.实现用户登录功能: 通过session来实现用户登录功能.在用户登录时,将用户的相关信息放在HttpSession对象用,其中HttpSession对象可以通过HttpServletRequest的getSession方法获得.同时,HttpSession对象对应Jsp内置对象session,在jsp页面中也可以通过session来访问,如通过jstl标签库来访问session中的内容: Html代码   <c:if test="${

Spring Boot实践教程:开篇

前言 ??Java项目开发Spring应该是最常被用到的框架了,但是老式的配置方式让人觉得特别的繁琐,虽然可以通过注解去简化xml文件的配置,但是有没有更简单的方式来帮我们完成这些重复性的事情呢?于是Spring Boot就出现了,Spring Boot极大的简化了Spring的应用开发,它采用约定优于配置的方式,让开发人员能够快速的搭建起项目并运行起来. ??我们在项目开发的过程中,总免不了要整合各种框架,类似什么SSM.SSH之类的,这些框架的整合过程是繁琐的,同时又是无聊的,因为大部分情况

Spring异常重试框架Spring Retry

Spring Retry支持集成到Spring或者Spring Boot项目中,而它支持AOP的切面注入写法,所以在引入时必须引入aspectjweaver.jar包. 快速集成的代码样例: @Configuration @EnableRetry public class Application { @Bean public Service service() { return new Service(); } } @Service class Service { @Retryable(Remo

java retry(重试) spring retry, guava retrying 详解

系列说明 java retry 的一步步实现机制. java-retry 源码地址 情景导入 简单的需求 产品经理:实现一个按条件,查询用户信息的服务. 小明:好的.没问题. 代码 UserService.java public interface UserService { /** * 根据条件查询用户信息 * @param condition 条件 * @return User 信息 */ User queryUser(QueryUserCondition condition); } Use