广告位联系
返回顶部
分享到

Spring Retry 重试实例详解

java 来源:互联网 作者:佚名 发布时间:2022-10-30 22:37:24 人浏览
摘要

spring-retry是什么? spring-retry是spring提供的一个重试框架,原本自己实现的重试机制,现在spring帮封装好提供更加好的编码体验。 重试的使用场景比较多,比如调用远程服务时,由于网

spring-retry是什么?

spring-retry是spring提供的一个重试框架,原本自己实现的重试机制,现在spring帮封装好提供更加好的编码体验。

重试的使用场景比较多,比如调用远程服务时,由于网络或者服务端响应慢导致调用超时,此时可以多重试几次。用定时任务也可以实现重试的效果,但比较麻烦,用Spring Retry的话一个注解搞定所有。话不多说,先看演示。

首先引入依赖

1

2

3

4

5

6

7

8

9

10

<dependency>

    <groupId>org.springframework.retry</groupId>

    <artifactId>spring-retry</artifactId>

    <version>1.3.4</version>

</dependency>

<dependency>

    <groupId>org.aspectj</groupId>

    <artifactId>aspectjweaver</artifactId>

    <version>1.9.9.1</version>

</dependency>

使用方式有两种:命令式和声明式

命令式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

/**

 * 命令式的方式使用Spring Retry

 */

@GetMapping("/hello")

public String hello(@RequestParam("code") Integer code) throws Throwable {

    RetryTemplate retryTemplate = RetryTemplate.builder()

            .maxAttempts(3)

            .fixedBackoff(1000)

            .retryOn(RemoteAccessException.class)

            .build();

    retryTemplate.registerListener(new MyRetryListener());

 

    String resp = retryTemplate.execute(new RetryCallback<String, Throwable>() {

        @Override

        public String doWithRetry(RetryContext context) throws Throwable {

            return helloService.hello(code);

        }

    });

 

    return resp;

}

定义一个RetryTemplate,然后调用execute方法,可配置项比较多,不一一列举

真正使用的时候RetryTemplate可以定义成一个Bean,例如:

1

2

3

4

5

6

7

8

9

10

11

12

13

@Configuration

public class RetryConfig {

    @Bean

    public RetryTemplate retryTemplate() {

        RetryTemplate retryTemplate = RetryTemplate.builder()

                .maxAttempts(3)

                .fixedBackoff(1000)

                .withListener(new MyRetryListener())

                .retryOn(RemoteAccessException.class)

                .build();

        return retryTemplate;

    }

}

业务代码:

1

2

3

4

5

6

7

8

9

10

11

12

/**

 * 命令式的方式使用Spring Retry

 */

@Override

public String hello(int code) {

    if (0 == code) {

        System.out.println("出错了");

        throw new RemoteAccessException("出错了");

    }

    System.out.println("处理完成");

    return "ok";

}

监听器实现:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

package com.example.retry.listener;

 

import org.springframework.retry.RetryCallback;

import org.springframework.retry.RetryContext;

import org.springframework.retry.RetryListener;

 

public class MyRetryListener implements RetryListener {

    @Override

    public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {

        System.out.println("open");

        return true;

    }

 

    @Override

    public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {

        System.out.println("close");

    }

 

    @Override

    public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {

        System.out.println("error");

    }

}

声明式(注解方式)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/**

 * 注解的方式使用Spring Retry

 */

@Retryable(value = Exception.class, maxAttempts = 2, backoff = @Backoff(value = 1000, delay = 2000, multiplier = 0.5))

@Override

public String hi(int code) {

    System.out.println("方法被调用");

    int a = 1/code;

    return "ok";

}

 

@Recover

public String hiRecover(Exception ex, int code) {

    System.out.println("重试结束");

    return "asdf";

}

这里需要主要的几点

  • @EnableRetry(proxyTargetClass = true/false)
  • @Retryable 修饰的方法必须是public的,而且不能是同一个类中调用
  • @Recover 修饰的方法签名必须与@Retryable修饰的方法一样,除了第一个参数外

1

2

3

4

5

6

7

/**

 * 注解的方式使用Spring Retry

 */

@GetMapping("/hi")

public String hi(@RequestParam("code") Integer code) {

    return helloService.hi(code);

}

1. 用法

声明式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

@Configuration

@EnableRetry

public class Application {

 

}

@Service

class Service {

    @Retryable(RemoteAccessException.class)

    public void service() {

        // ... do something

    }

    @Recover

    public void recover(RemoteAccessException e) {

       // ... panic

    }

}

命令式

1

2

3

4

5

6

7

8

9

RetryTemplate template = RetryTemplate.builder()

                .maxAttempts(3)

                .fixedBackoff(1000)

                .retryOn(RemoteAccessException.class)

                .build();

 

template.execute(ctx -> {

    // ... do something

});

2. RetryTemplate

为了自动重试,Spring Retry 提供了 RetryOperations 重试操作策略

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public interface RetryOperations {

 

    <T> T execute(RetryCallback<T> retryCallback) throws Exception;

 

    <T> T execute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback)

        throws Exception;

 

    <T> T execute(RetryCallback<T> retryCallback, RetryState retryState)

        throws Exception, ExhaustedRetryException;

 

    <T> T execute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback,

        RetryState retryState) throws Exception;

 

}

基本回调是一个简单的接口,允许插入一些要重试的业务逻辑:

1

2

3

4

public interface RetryCallback<T> {

 

    T doWithRetry(RetryContext context) throws Throwable;

}

回调函数被尝试,如果失败(通过抛出异常),它将被重试,直到成功或实现决定中止。

RetryOperations最简单的通用实现是RetryTemplate

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

RetryTemplate template = new RetryTemplate();

 

TimeoutRetryPolicy policy = new TimeoutRetryPolicy();

policy.setTimeout(30000L);

 

template.setRetryPolicy(policy);

 

Foo result = template.execute(new RetryCallback<Foo>() {

 

    public Foo doWithRetry(RetryContext context) {

        // Do stuff that might fail, e.g. webservice operation

        return result;

    }

 

});

从Spring Retry 1.3开始,RetryTemplate支持流式配置:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

RetryTemplate.builder()

      .maxAttempts(10)

      .exponentialBackoff(100, 2, 10000)

      .retryOn(IOException.class)

      .traversingCauses()

      .build();

 

RetryTemplate.builder()

      .fixedBackoff(10)

      .withinMillis(3000)

      .build();

 

RetryTemplate.builder()

      .infiniteRetry()

      .retryOn(IOException.class)

      .uniformRandomBackoff(1000, 3000)

      .build();

3. RecoveryCallback

当重试耗尽时,RetryOperations可以将控制传递给不同的回调:RecoveryCallback。

1

2

3

4

5

6

7

8

9

Foo foo = template.execute(new RetryCallback<Foo>() {

    public Foo doWithRetry(RetryContext context) {

        // business logic here

    },

  new RecoveryCallback<Foo>() {

    Foo recover(RetryContext context) throws Exception {

          // recover logic here

    }

});

4. Listeners

1

2

3

4

5

6

7

8

9

10

public interface RetryListener {

 

    void open(RetryContext context, RetryCallback<T> callback);

 

    void onSuccess(RetryContext context, T result);

 

    void onError(RetryContext context, RetryCallback<T> callback, Throwable e);

 

    void close(RetryContext context, RetryCallback<T> callback, Throwable e);

}

在最简单的情况下,open和close回调在整个重试之前和之后,onSuccess和onError应用于个别的RetryCallback调用,onSuccess方法在成功调用回调之后被调用。

5. 声明式重试

有时,你希望在每次业务处理发生时都重试一些业务处理。这方面的典型例子是远程服务调用。Spring Retry提供了一个AOP拦截器,它将方法调用封装在RetryOperations实例中。RetryOperationsInterceptor执行被拦截的方法,并根据提供的RepeatTemplate中的RetryPolicy在失败时重试。

你可以在 @Configuration 类上添加一个 @EnableRetry 注解,并且在你想要进行重试的方法(或者类)上添加 @Retryable 注解,还可以指定任意数量的重试监听器。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

@Configuration

@EnableRetry

public class Application {

 

    @Bean

    public Service service() {

        return new Service();

    }

 

    @Bean public RetryListener retryListener1() {

        return new RetryListener() {...}

    }

 

    @Bean public RetryListener retryListener2() {

        return new RetryListener() {...}

    }

 

}

 

@Service

class Service {

    @Retryable(RemoteAccessException.class)

    public service() {

        // ... do something

    }

}

可以使用 @Retryable 的属性类控制 RetryPolicy 和 BackoffPolicy

1

2

3

4

5

6

7

@Service

class Service {

    @Retryable(maxAttempts=12, backoff=@Backoff(delay=100, maxDelay=500))

    public service() {

        // ... do something

    }

}

如果希望在重试用尽时采用替代代码返回,则可以提供恢复方法。方法应该声明在与@Retryable实例相同的类中,并标记为@Recover。返回类型必须匹配@Retryable方法。恢复方法的参数可以包括抛出的异常和(可选地)传递给原始可重试方法的参数(或者它们的部分列表,只要在需要的最后一个之前不省略任何参数)。

1

2

3

4

5

6

7

8

9

10

11

@Service

class Service {

    @Retryable(RemoteAccessException.class)

    public void service(String str1, String str2) {

        // ... do something

    }

    @Recover

    public void recover(RemoteAccessException e, String str1, String str2) {

       // ... error handling making use of original args if required

    }

}

若要解决可选择用于恢复的多个方法之间的冲突,可以显式指定恢复方法名称。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

@Service

class Service {

    @Retryable(recover = "service1Recover", value = RemoteAccessException.class)

    public void service1(String str1, String str2) {

        // ... do something

    }

 

    @Retryable(recover = "service2Recover", value = RemoteAccessException.class)

    public void service2(String str1, String str2) {

        // ... do something

    }

 

    @Recover

    public void service1Recover(RemoteAccessException e, String str1, String str2) {

        // ... error handling making use of original args if required

    }

 

    @Recover

    public void service2Recover(RemoteAccessException e, String str1, String str2) {

        // ... error handling making use of original args if required

    }

}

https://github.com/spring-projects/spring-retry


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://www.cnblogs.com/cjsblog/p/16826063.html
相关文章
  • (最新最完整)JDK1.8下载、安装和环境配置超详细教

    (最新最完整)JDK1.8下载、安装和环境配置超详细教
    一、下载安装包 1. JDK1.8百度云下载路径: 百度网盘下载 链接: https://pan.baidu.com/s/1H54MWN6suutVouYGe5e4og?pwd=tetv 提取码: tetv 网盘放的是jdk1.8版本
  • Spring Retry 重试实例详解

    Spring Retry 重试实例详解
    spring-retry是什么? spring-retry是spring提供的一个重试框架,原本自己实现的重试机制,现在spring帮封装好提供更加好的编码体验。 重试的使用
  • SpringCloud hystrix断路器与局部降级全面介绍

    SpringCloud hystrix断路器与局部降级全面介绍
    服务降级 服务压力剧增的时候,根据当前的业务情况及流量对一些服务和页面有策略的降级,以此缓解服务器的压力,以保证核心任务的进
  • SpringCloud hystrix断路器与全局解耦全面介绍

    SpringCloud hystrix断路器与全局解耦全面介绍
    第七章中在ProductController 和OrderController 中都使用了局部服务降级,但同时也导致两个问题, 通过观察两个局部降级的案例,可以发现: 每
  • SpringBoot自定义错误处理逻辑介绍

    SpringBoot自定义错误处理逻辑介绍
    1. 自定义错误页面 将自定义错误页面放在 templates 的 error 文件夹下,SpringBoot 精确匹配错误信息,使用 4xx.html 或者 5xx.html 页面可以打印错误
  • Java实现手写一个线程池的代码

    Java实现手写一个线程池的代码
    线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和
  • Java实现断点续传功能的代码

    Java实现断点续传功能的代码
    题目实现:网络资源的断点续传功能。 二、解题思路 获取要下载的资源网址 显示网络资源的大小 上次读取到的字节位置以及未读取的字节
  • 你可知HashMap为什么是线程不安全的
    HashMap 的线程不安全 HashMap 的线程不安全主要体现在下面两个方面 在 jdk 1.7 中,当并发执行扩容操作时会造成环形链和数据丢失的情况 在
  • ArrayList的动态扩容机制的介绍

    ArrayList的动态扩容机制的介绍
    对于 ArrayList 的动态扩容机制想必大家都听说过,之前的文章中也谈到过,不过由于时间久远,早已忘却。 所以利用这篇文章做做笔记,加
  • JVM基础之字节码的增强技术介绍

    JVM基础之字节码的增强技术介绍
    字节码增强技术 在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计