spring-retry重试机制使用

使用背景

在实际工作过程中,因网络波动、服务并发限制等原因造成接口服务调用失败,MQ发送消息失败等,可以采取重试手段,重试机制是常见的一种处理问题的手段。

重试方式有很多,如可以自己通过代码逻辑实现,但不是很优雅。

而spring-retry可以以优雅的方式实现重试:

Retry重试框架,支持AOP切入的方式使用,而且能使用注解;像我们关心的重试次数、重试延迟时间、重试触发条件、重试的回调方法等等都能很轻松结合注解以一种类似配置参数的方式去实现,优雅无疑。

本文章简述springboot+retry的使用。

1、添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jia</groupId>
    <artifactId>bill</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>bill</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 重试依赖-->
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId >
            <artifactId>aspectjweaver</artifactId >
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、在启动类上加@EnableRetry注解,表示启动重试机制

 1 package com.jia.bill;
 2
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.retry.annotation.EnableRetry;
 6
 7 @EnableRetry
 8 @SpringBootApplication
 9 public class BillApplication {
10
11     public static void main(String[] args) {
12         SpringApplication.run(BillApplication.class, args);
13     }
14
15 }

3、定义一个简单的需要重试的接口服务

package com.jia.bill.service;

public interface TestRetryService {
    int retryServiceTest(int code) throws Exception;
}
package com.jia.bill.service.serviceImpl;

import com.jia.bill.service.TestRetryService;import org.springframework.retry.annotation.Backoff;import org.springframework.retry.annotation.Recover;import org.springframework.retry.annotation.Retryable;import org.springframework.stereotype.Service;

import java.time.LocalTime;

@Servicepublic class TestRetryServiceImpl implements TestRetryService {

    @Override    @Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))    public int retryServiceTest(int code) throws Exception{        System.out.println("retryServiceTest被调用,时间:"+ LocalTime.now());
        if (code==0){            throw new Exception("请求参数为0,出现异常");//            throw new IllegalArgumentException("非法数据");        }        System.out.println("retryServiceTest被调用,情况对头了!");
        return 200;    }

    @Recover    public int recover(Exception e){        System.out.println("重试次数结束后还有异常,回调方法开始执行");        //可调用其余的方法        return 400;    }

}

当调用TestRetryServiceImpl 中的retryServiceTest时,如果抛出了异常Exception,就会被重试,重试3次。

但是如果三次都失败了,并且写了recover方法时,就会执行recover方法了。如果没有此方法会直接抛出异常。

其中注解解释:

@Retryable : 注解方式标记当前方法会使用重试机制

   里面的 value: 重试的触发机制,当遇到Exception异常的时候,触发;
           maxAttempts: 重试的次数(包括第一次调用,也就是说如果设置3次,调用一次后,如果一直失败触发重试,那么还当前方法还会调用2次);
           delay:重试的延迟时间,也就是距离上一次重试方法调用的间隔,单位毫秒
          multiplier: delay间隔时间的倍数,也就是说,第一次重试间隔如果是2000ms,那第二次重试的时候就是2000ms 乘以这个倍数1.5,就是3000ms;

maxDelay:重试次数之间的最大时间间隔,默认为0,即忽略,如果小于delay的设置,则默认为30000L;
@Recover,也就是用注解方式标记当期方法为回调方法,可以看到传参里面写的是 Exception e,这个是作为回调的接头暗号(重试次数用完了,还是失败,我们抛出这个Exception e通知触发这个回调方法)。

4、controller简单编写

package com.jia.bill.controller;

import com.jia.bill.service.TestRetryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestRetryController {
    @Autowired
    TestRetryService testRetryServiceImpl;

    @GetMapping("/testRetry")
    public String testRetry() throws Exception {
        int code = 0;
        int result = testRetryServiceImpl.retryServiceTest(code);
        return "result:" + result;
    }

}

5、运行结果

retryServiceTest,时间:19:12:24.590
retryServiceTest,时间:19:12:26.591
retryServiceTest,时间:19:12:29.592
重试次数结束后还有异常,回调方法开始执行

原文地址:https://www.cnblogs.com/happyjia/p/12219183.html

时间: 2024-08-29 21:51:38

spring-retry重试机制使用的相关文章

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

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

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

一文详解Spring Cloud Feign重试机制

前言 Feign组件默认使用Ribbon的重试机制并增加了根据状态码判断重试机制,默认情况下是不启用的.Feign使用的是Spring Retry组件,需要引入依赖才能启用. 一.POM引入Spring Retry <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> 二

SpringCloud | FeignClient和Ribbon重试机制区别与联系

在spring cloud体系项目中,引入的重试机制保证了高可用的同时,也会带来一些其它的问题,如幂等操作或一些没必要的重试. 今天就来分别分析一下 FeignClient 和 Ribbon 重试机制的实现原理和区别,主要分为三点: 1)FeignClient重试机制分析 2)Ribbon重试机制分析 3)FeignClient和Ribbon重试机制的区别于联系 1)FeignClient 重试机制分析: FeignClient 重试机制的实现原理相对简单.首先看一下feignClient处理请

Volley超时重试机制详解

Volley超时重试机制 基础用法 Volley为开发者提供了可配置的超时重试机制,我们在使用时只需要为我们的Request设置自定义的RetryPolicy即可. 参考设置代码如下: int DEFAULT_TIMEOUT_MS = 10000; int DEFAULT_MAX_RETRIES = 3; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<S

为你的代码加上一层重试机制

为代码加上重试机制 1.前言:对于经常跟网络编程打交道的你来说,并不是你的每次Request,Server都会给你想要的Response.重试机制虽然并不能解决这种情况,但是却可以大大减少这种情况的发生. 2.介绍下重试机制类:RetryUtil.cs 使用了委托,代码很短,也不难理解. 1 public class RetryUtil 2 { 3 public delegate void NoArgumentHandler(); 4 /// <summary> 5 /// retry mec

guava的重试机制guava-retrying使用

1,添加maven依赖 <dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency> 2,定义重试机制 Retryer<CMSResultDTO> smsRetryer = RetryerBuilder.

PHP-RESQUE重试机制

因为PHP-Resque 的重试需要自己写,网上又没啥轮子,而且resque也很久不更新了,所以自己研究下resque的源码,然后也借鉴了Laravel的队列重试机制,实现了PHP-Resque的重试机制. 设计思路 阅读resque源码,我们知道,resque把失败的队列的数据都放在了resque:failed列表,数据如下. 我的项目是在yii2下统一处理resque的,我直接resque源码在新增了retry方法,在每一个failJob的payload增加了attempts尝试次数,一开始