天天看点

Spring Retry 重试机制 10 分钟立马掌握特别鸣谢:https://blog.csdn.net/Revivedsun/article/details/53401335参考方式:以下内容都是demo,直接复制粘贴到项目中即可。1.自定义手写重试机制2.Spring Retry 入门

特别鸣谢:https://blog.csdn.net/Revivedsun/article/details/53401335

参考方式:以下内容都是demo,直接复制粘贴到项目中即可。

1.自定义手写重试机制

参考地址:https://blog.csdn.net/u010081710/article/details/77879129

参考地址:https://blog.csdn.net/xiaolyuh123/article/details/80209815

/**
 * 手写重试机制
 */
public class MyJavaRetry {

    public static void main(String[] args) throws InterruptedException {
        // 重试次数 3 次
        int maxRryTimes = 3;
        // 时间间隔 3 秒
        int intervalTime = 3;
        // 重试次数
        int redo = 1;
        
        while (redo <= maxRryTimes) {
            
            try {
                
                doBuinessLogic(redo); // 业务处理,可能需要重试的业务
                break;                //执行成功后直接退出此循环
            } catch (Exception e) {   //异常时,重试次数增加
                
                redo++;
                // 优先使用TimeUnit类中的sleep() 而不是Thread.sleep(4*60*1000);
                TimeUnit.SECONDS.sleep(intervalTime);
                
                continue;
            }
        }

    }

    private static void doBuinessLogic(int redo) {
        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (redo < 3) {
            System.err.println("第" + redo + "次执行doBuinessLogic()" + "开始执行时间:" + s.format(new Date()) + "执行失败");
            throw new RuntimeException();
        }
        
        System.err.println("第" + redo + "次执行doBuinessLogic()" + "开始执行时间:" + s.format(new Date()) + "执行成功");
    }
}
           

2.Spring Retry 入门

2.1 maven项目pom.xml

<dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
           

2.2 SpringRetryDemo

package com.retry;

import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.Test;
import org.springframework.classify.Classifier;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.retry.RetryPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.backoff.ExponentialRandomBackOffPolicy;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.backoff.NoBackOffPolicy;
import org.springframework.retry.backoff.Sleeper;
import org.springframework.retry.backoff.UniformRandomBackOffPolicy;
import org.springframework.retry.policy.AlwaysRetryPolicy;
import org.springframework.retry.policy.CompositeRetryPolicy;
import org.springframework.retry.policy.ExceptionClassifierRetryPolicy;
import org.springframework.retry.policy.NeverRetryPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.policy.TimeoutRetryPolicy;
import org.springframework.retry.support.RetryTemplate;


/**
 * spring-retry 版本 1.2.2
 * 
 * Spring-retry提供了RetryOperations接口的实现类RetryTemplate。
 * 通过RetryTemplate来完成重试,下面是使用RetryTemplate重试的一些简单例子。
 * 
 */
public class SpringRetryDemo {
    
    private static final int NOTIFY_RETRY_TIMES = 3;

    /**
     * 简介:
     * 
     * Spring-retry提供的RetryOperations接口,该接口提供了若干方法来执行重试操作
     * 
     * public interface RetryOperations {
     *       <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback) throws E;
     *       
     *       <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback, RecoveryCallback<T> recoveryCallback) throws E;
     *       
     *       <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback, RetryState retryState) throws E, ExhaustedRetryException;
     *   
     *       <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback, RecoveryCallback<T> recoveryCallback, RetryState retryState) throws E;
     * }
     * 
     * 调用者通过传入RetryCallback来完成调用者的重试操作。如果callback执行失败(抛出某些异常),那么会按照调用者设定的策略进行重试。
     * 重试操作直到成功,或根据使用者设定的条件而退出。
     * 
     * RetryCallback的接口定义如下:
     * 
     * public interface RetryCallback<T, E extends Throwable> {
     * 
     *      T doWithRetry(RetryContext context) throws E;
     * }
     * 
     */

    
    /**
     * TimeoutRetryPolicy策略(注:不是间隔多长时间进行重试的那个时间)
     * 
     * 代码定义了TimeoutRetryPolicy策略,TimeoutRetryPolicy超时时间默认是1秒。
     * TimeoutRetryPolicy超时是指在execute方法内部,从open操作开始到调用
     * TimeoutRetryPolicy的canRetry方法这之间所经过的时间。
     * 这段时间未超过TimeoutRetryPolicy定义的超时时间,那么执行操作,否则抛出异常。
     * 
     * protected <T, E extends Throwable> T doExecute(RetryCallback<T, E> retryCallback,RecoveryCallback<T> recoveryCallback, RetryState state) throws E,ExhaustedRetryException {
     *      ……略
     *      RetryContext context = open(retryPolicy, state);                 
     *      ……略
     *      while (canRetry(retryPolicy, context) &&   !context.isExhaustedOnly())   
     *      // 调用canRetry检查是否可以重试
     *      ……略
     *   }
     *
     */
    @Test
    public void timeoutRetryPolicyTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();

        // 超时重试策略
        TimeoutRetryPolicy policy = new TimeoutRetryPolicy();
        // 超时时间 默认 1000 毫秒
        policy.setTimeout(2000);
        
        // 设置重试策略
        template.setRetryPolicy(policy);

        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {

                    public String doWithRetry(RetryContext context) throws InterruptedException {
                   
                        System.out.println("执行Buiness logic");
                        // TODO 对这个策略模式的理解还是模糊 还为理解超时到底是哪个地方超时
                        // 等待3秒
                        TimeUnit.SECONDS.sleep(3);
                        
                        return "SUCCESS";
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                        return "failed callback";
                    }
                }
        );
        
        System.out.println(result);
    }
    
    /**
     * SimpleRetryPolicy 策略
     * 
     * will execute the callback at least once, and as many as 3 times.
     * 该策略定义了对指定的异常进行若干次重试。默认情况下,对Exception异常及其子类重试3次.
     * 如果创建SimpleRetryPolicy并指定重试异常map,可以选择性重试或不进行重试.
     * 
     */
    @SuppressWarnings("unused")
    @Test
    public void simpleRetryPolicyTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();
        
        
        // 简单重试策略 example one
        SimpleRetryPolicy policy1 = new SimpleRetryPolicy();
        // 最大重试次数  默认3次  这里设置为5次
        policy1.setMaxAttempts(5);
        
        // 简单重试策略 example two  1 重试次数5次  2Exception及其子类都进行异重试
        // Set the max attempts including the initial attempt before retrying
        // and retry on all exceptions (this is the default):
        SimpleRetryPolicy policy2 = new SimpleRetryPolicy(5, Collections.singletonMap(Exception.class, true));

        // 简单重试策略 example three
        Map<Class<? extends Throwable>, Boolean> retryableExceptionMaps = new HashMap<Class<? extends Throwable>, Boolean>();;
        // 空指针异常进行重试  true 进行重试(当Map中的的value为false,那么执行方法,随后抛出异常不进行重试。)
        retryableExceptionMaps.put(NullPointerException.class, true);
        SimpleRetryPolicy policy3 = new SimpleRetryPolicy(5, retryableExceptionMaps);
        
        // 设置重试策略
        template.setRetryPolicy(policy1);
//        template.setRetryPolicy(policy2);
//        template.setRetryPolicy(policy3);

        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {

                    public String doWithRetry(RetryContext context) throws InterruptedException {
                   
                        if (true) {
                            System.out.println("执行Buiness logic. NPE");
                            // 抛出异常
                            throw new NullPointerException("NullPointerException");
                        }
                        
                        return "SUCCESS";
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                        return "failed callback";
                    }
                }
        );
        
        System.out.println(result);
    }
    
    /**
     * NeverRetryPolicy 策略
     * 
     * 执行一次待执行操作,若出现异常后不进行重试。
     * 
     */
    @Test
    public void neverRetryPolicyTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();

        // 从不重试策略
        NeverRetryPolicy  policy = new NeverRetryPolicy();
        
        // 设置重试策略
        template.setRetryPolicy(policy);

        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {

                    public String doWithRetry(RetryContext context) throws InterruptedException {
                   
                        System.out.println("执行Buiness logic. NPE");
                        // 抛出异常
                        throw new NullPointerException("NullPointerException");
                        
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                        return "failed callback";
                    }
                }
        );
        
        System.out.println(result);
    }
    
    
    /**
     * AlwaysRetryPolicy 策略
     * 
     * 异常后一直重试直到成功。
     * 
     */
    @Test
    public void alwaysRetryPolicyTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();
        
        // 一直重试策略
        AlwaysRetryPolicy  policy = new AlwaysRetryPolicy();
        
        // 设置重试策略
        template.setRetryPolicy(policy);
        
        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {
                    
                    public String doWithRetry(RetryContext context) throws InterruptedException {
                        
                        System.out.println("执行Buiness logic. NPE");
                        // 抛出异常
                        throw new NullPointerException("NullPointerException");
                        
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                        return "failed callback";
                    }
                }
        );
        
        System.out.println(result);
    }
    
    
    /**
     * ExceptionClassifierRetryPolicy 策略
     * 
     * 根据产生的异常选择重试策略。
     * 
     */
    @SuppressWarnings("serial")
    @Test
    public void exceptionClassifierRetryPolicyTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();
        
        
        /* setPolicyMap 与 setExceptionClassifier 使用一个即可。*/
        
        // 方式 1 setPolicyMap
        // 根据异常设置重试策略
        ExceptionClassifierRetryPolicy policy1 = new ExceptionClassifierRetryPolicy();
        
        Map<Class<? extends Throwable>, RetryPolicy> policyMap = new HashMap<Class<? extends Throwable>, RetryPolicy>();
        // 抛出TimeoutException采用AlwaysRetryPolicy策略
        policyMap.put(TimeoutException.class, new AlwaysRetryPolicy());
        // 抛出NullPointerException采用NeverRetryPolicy策略
        policyMap.put(NullPointerException.class, new NeverRetryPolicy());
        // 异常重试策略map
        policy1.setPolicyMap(policyMap);
        
        // 方式 2 setExceptionClassifier
        // 根据异常设置重试策略
        ExceptionClassifierRetryPolicy policy2 = new ExceptionClassifierRetryPolicy();
        // 此外可以通过setExceptionClassifier来为异常指定重试策略。
        Classifier<Throwable, RetryPolicy> exceptionClassifier = new Classifier<Throwable, RetryPolicy>(){
            public RetryPolicy classify(Throwable classifiable) {
                if(classifiable instanceof TimeoutException)
                    return new SimpleRetryPolicy();
                return new NeverRetryPolicy();
            }

        };
        policy2.setExceptionClassifier(exceptionClassifier);
        
        // 设置重试策略
        template.setRetryPolicy(policy1);
//        template.setRetryPolicy(policy2);
        
        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {
                    
                    public String doWithRetry(RetryContext context) throws Exception {
                        
                        int number = new Random().nextInt(10) + 1;
                        if (number > 5) {
                            
                            System.out.println("执行Buiness logic. NPE");
                            // 抛出异常
                            throw new NullPointerException("NullPointerException");
                        } else {
                            
                            System.out.println("执行Buiness logic. TE");
                            // 抛出异常
                            throw new TimeoutException("TimeoutException");
                        }
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                        return "failed callback";
                    }
                }
        );
        
        System.out.println(result);
    }
    
    /**
     * CompositeRetryPolicy 策略
     * 
     * 用户指定一组策略,随后根据optimistic选项来确认如何重试。
     * 
     * 下面的代码中创建CompositeRetryPolicy策略,并创建了RetryPolicy数组,
     * 数组有两个具体策略SimpleRetryPolicy与AlwaysRetryPolicy。
     * 
     * optimistic = true
     * 当CompositeRetryPolicy设置optimistic为true时,Spring-retry会顺序遍历RetryPolicy[]数组,如果有一个重试策略可重试,
     * 例如SimpleRetryPolicy没有达到重试次数,那么就会进行重试
     * 
     * optimistic = false
     * 如果optimistic选项设置为false。那么有一个重试策略无法重试,那么就不进行重试。
     * 例如SimpleRetryPolicy达到重试次数不能再重试,而AlwaysRetryPolicy可以重试,那么最终是无法重试的。
     *  
     * 以下代码,设置setOptimistic(true),而AlwaysRetryPolicy一直可重试,那么最终可以不断进行重试。
     *  
     */
    @Test
    public void compositeRetryPolicyTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();
        
        // 混合策略
        CompositeRetryPolicy policy = new CompositeRetryPolicy();
        // 策略组
        RetryPolicy[] polices = {new SimpleRetryPolicy(), new AlwaysRetryPolicy()};
        policy.setPolicies(polices);
        policy.setOptimistic(true);
        
        // 设置重试策略
        template.setRetryPolicy(policy);
        
        try {
            

        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {
                    
                    public String doWithRetry(RetryContext context) throws Exception {
                        
                        int number = new Random().nextInt(10) + 1;
                        if (number > 5) {
                            
                            System.out.println("执行Buiness logic. NPE");
                            // 抛出异常
                            throw new NullPointerException("NullPointerException");
                        } else {
                            
                            System.out.println("执行Buiness logic. TE");
                            // 抛出异常
                            throw new TimeoutException("TimeoutException");
                        }
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                        return "failed callback";
                    }
                }
                );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 退避(BackOff)策略
     * 
     * 当操作执行失败时,根据设置的重试策略进行重试。通过BackoffPolicy可以设定再次重试的时间间隔。
     * 
     * 接口:
     * public interface BackOffPolicy {
     *       BackOffContext start(RetryContext context);
     *       void backOff(BackOffContext backOffContext) throws BackOffInterruptedException;
     * }
     * 
     * BackOff策略接口的具体实现:
     * 
     * interface BackOffPolicy
     *      // 实现BackOff接口的抽象类
     *      abstract StatelessBackOffPolicy
     *          class FixedBackOffPolicy // 在等待一段固定的时间后,再进行重试。默认为1秒。
     *          class NoBackOffPolicy    // 实现了空方法,因此采用次策略,重试不会等待。这也是RetryTemplate采用的默认退避(backOff)策略
     *          class UniformRandomBackOffPolicy // 均匀随机退避策略,等待时间为 最小退避时间 + [0,最大退避时间 - 最小退避时间)间的一个随机数,如果最大退避时间等于最小退避时间那么等待时间为0。
     *      // 继承BackOff接口的接口
     *      interface SleepingBackOffPolicy
     *          class ExponentialBackOffPolicy // 指数退避策略 ,每次等待时间为 等待时间 = 等待时间 * N ,即每次等待时间为上一次的N倍。如果等待时间超过最大等待时间,那么以后的等待时间为最大等待时间。
     *              // 该类是ExponentialBackOffPolicy的子类
     *              class ExponentialRandomBackOffPolicy // 指数随机策略
     *          class FixedBackOffPolicy    // 与StatelessBackoffPolicy的同名实现类返回等待时间的方法是一致的。而两者的主要区别是,SleepingbackOffPolicy可以设置用户定义的Sleeper。
     *          class UniformRandomBackOffPolicy // 与StatelessBackoffPolicy的同名实现类返回等待时间的方法是一致的。而两者的主要区别是,SleepingbackOffPolicy可以设置用户定义的Sleeper。
     *
     */
    
    /**
     * 实现BackOff接口的抽象类
     * StatelessBackoffPolicy 抽象类下的退避策略
     * 
     */
    @SuppressWarnings("unused")
    @Test
    public void statelessBackoffPolicyTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();
        
        // 简单重试策略
        SimpleRetryPolicy policy = new SimpleRetryPolicy(); // 默认重试3次
        // 设置重试策略
        template.setRetryPolicy(policy);
        
        // 1. 固定退避策略
        FixedBackOffPolicy backOffPolicy1 = new FixedBackOffPolicy();
        backOffPolicy1.setBackOffPeriod(2000); // Default back off period - 1000ms.

        // 2. 默认退避策略 不等待,直接重试
        NoBackOffPolicy backOffPolicy2 = new NoBackOffPolicy();
        
        // 3. 均匀随机退避策略 
        UniformRandomBackOffPolicy backOffPolicy3 = new UniformRandomBackOffPolicy();
        // 等待时间为 最小退避时间 + [0, 最大退避时间 - 最小退避时间)间的一个随机数 (如果最大退避时间等于最小退避时间那么等待时间为0)
        backOffPolicy3.setMinBackOffPeriod(2000); // Default min back off period - 500ms.
        backOffPolicy3.setMaxBackOffPeriod(5000); // Default max back off period - 1500ms.
        
        // 设置退避策略
        template.setBackOffPolicy(backOffPolicy1);
//        template.setBackOffPolicy(backOffPolicy2);
//        template.setBackOffPolicy(backOffPolicy3);
        
        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {
                    
                    public String doWithRetry(RetryContext context) throws Exception {
                        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
                        int number = new Random().nextInt(10) + 1;
                        if (number > 5) {
                            
                            System.out.println("执行Buiness logic. NPE" + "开始执行时间:" + s.format(new Date()));
                            // 抛出异常
                            throw new NullPointerException("NullPointerException");
                        } else {
                            
                            System.out.println("执行Buiness logic. TE" + "开始执行时间:" + s.format(new Date()));
                            // 抛出异常
                            throw new TimeoutException("TimeoutException");
                        }
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                        return "failed callback";
                    }
                }
                );
        
        System.out.println(result);
    }
    
    
    /**
     * 继承BackOff接口的接口
     * SleepingbackOffPolicy 接口下的退避策略
     * 
     */
    @SuppressWarnings("serial")
    @Test
    public void sleepingbackOffPolicyTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();
        
        // 简单重试策略
        SimpleRetryPolicy policy = new SimpleRetryPolicy();
        // 重试5次
        policy.setMaxAttempts(5);
        // 设置重试策略
        template.setRetryPolicy(policy);
        
        
        // 1. 指数退避策略
        ExponentialBackOffPolicy backOffPolicy1 = new ExponentialBackOffPolicy();
        // 每次等待时间为 等待时间 = 等待时间 * N ,即每次等待时间为上一次的N倍。 (如果等待时间超过最大等待时间,那么以后的等待时间为最大等待时间。)
        // 以下设置 初始时间间隔为2000毫秒,N = 3,¸最大间隔为6000毫秒,那么从第3次重试开始,以后每次等待时间都为6000毫秒。
        backOffPolicy1.setInitialInterval(2000);// 等待时间 The default 'initialInterval' value - 100 millisecs.
        backOffPolicy1.setMultiplier(3);// 等待倍数 The default 'multiplier' value - value 2 (100% increase per backoff).
        backOffPolicy1.setMaxInterval(6000);//最大等待时间  The default maximum backoff time (30 seconds).
        
        // 2. 指数随机退避策略
        ExponentialRandomBackOffPolicy backOffPolicy2 = new ExponentialRandomBackOffPolicy();
        // 算法是 等待时间 = 等待时间 * (1 + Random(随机数) * (N - 1))
        backOffPolicy2.setInitialInterval(2000);// 等待时间 The default 'initialInterval' value - 100 millisecs.
        backOffPolicy2.setMultiplier(3);// 等待倍数 The default 'multiplier' value - value 2 (100% increase per backoff).
        
        // 3. 固定退避策略
        FixedBackOffPolicy backOffPolicy3 = new FixedBackOffPolicy();
        backOffPolicy3.setBackOffPeriod(2000); // Default back off period - 1000ms.
        // 用户自定义 sleeper 不知道能干啥 不懂
        Sleeper sleeper3 = new Sleeper() {
            
            @Override
            public void sleep(long backOffPeriod) throws InterruptedException {
                // 不理解这个的作用
                TimeUnit.SECONDS.sleep(10);
                System.out.println("sleeper");
            }
        };
        backOffPolicy3.setSleeper(sleeper3);
        
        // 4. 均匀随机退避策略 
        UniformRandomBackOffPolicy backOffPolicy4 = new UniformRandomBackOffPolicy();
        // 等待时间为 最小退避时间 + [0, 最大退避时间 - 最小退避时间)间的一个随机数 (如果最大退避时间等于最小退避时间那么等待时间为0)
        backOffPolicy4.setMinBackOffPeriod(2000); // Default min back off period - 500ms.
        backOffPolicy4.setMaxBackOffPeriod(5000); // Default max back off period - 1500ms.
        // 用户自定义 sleeper 不知道能干啥 不懂
        Sleeper sleeper4 = new Sleeper() {
            
            @Override
            public void sleep(long backOffPeriod) throws InterruptedException {
             // 不理解这个的作用
                TimeUnit.SECONDS.sleep(10);
                System.out.println("sleeper");
            }
        };
        backOffPolicy4.setSleeper(sleeper4);
        
        
        // 设置退避策略
        template.setBackOffPolicy(backOffPolicy1);
//        template.setBackOffPolicy(backOffPolicy2);
//        template.setBackOffPolicy(backOffPolicy3);
//        template.setBackOffPolicy(backOffPolicy4);
        
        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {
                    
                    public String doWithRetry(RetryContext context) throws Exception {
                        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        int number = new Random().nextInt(10) + 1;
                        if (number > 5) {
                            
                            System.out.println("执行Buiness logic. NPE" + "开始执行时间:" + s.format(new Date()));
                            // 抛出异常
                            throw new NullPointerException("NullPointerException");
                        } else {
                            
                            System.out.println("执行Buiness logic. TE" + "开始执行时间:" + s.format(new Date()));
                            // 抛出异常
                            throw new TimeoutException("TimeoutException");
                        }
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                        return "failed callback";
                    }
                }
                );
        
        System.out.println(result);
    }
    
    /**
     * 监听器
     * 
     */
    @Test
    public void retryListenerTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();
        
        // 简单重试策略
        SimpleRetryPolicy policy = new SimpleRetryPolicy(); // 默认重试3次
        // 设置重试策略
        template.setRetryPolicy(policy);
        
        // 固定时间退避策略
        FixedBackOffPolicy backOffPolicy1 = new FixedBackOffPolicy();
        backOffPolicy1.setBackOffPeriod(2000); // Default back off period - 1000ms.
        // 设置退避策略
        template.setBackOffPolicy(backOffPolicy1);
        
        /**
         * 
         * 上述代码注册了两个Listener,Listener中的三个实现方法,onError, open, close会在执行重试操作时被调用,
         * 在RetryTemplate中doOpenInterceptors, doCloseInterceptors, doOnErrorInterceptors
         * 会调用监听器对应的open, close, onError 方法。
         *
         * doOpenInterceptors方法在第一次重试之前会被调用,如果该方法返回true,则会继续向下直接,如果返回false,则抛出异常,停止重试。
         * 
         * doOnErrorInterceptors 在抛出异常后执行,
         *   
         * doCloseInterceptors 会在重试操作执行完毕后调用。
         * 
         */
        
        // 监听器1
        RetryListener retryListener1 = new RetryListener() {
            
            @Override
            public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
                System.out.println("1-open");
                return true;
            }
            
            @Override
            public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
                    Throwable throwable) {
                System.out.println("1-onError");
            }
            
            @Override
            public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
                    Throwable throwable) {
                System.out.println("1-close");
            }
        };
        
        // 监听器1
        RetryListener retryListener2 = new RetryListener() {
            
            @Override
            public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
                System.out.println("2-open");
                return true;
            }
            
            @Override
            public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
                    Throwable throwable) {
                System.out.println("2-onError");
            }
            
            @Override
            public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
                    Throwable throwable) {
                System.out.println("2-close");
            }
        };
        // 监听组
        RetryListener[] listeners = {retryListener1, retryListener2};
        /*
         *  设置监听器  当注册多个Listener时,open方法按会按Listener的注册顺序调用,
         *  而onError和close则按Listener注册的顺序逆序调用。
         *  
         *  open    初始重试调用
         *  onError 发生异常就调用
         *  close   重试次数全部结束调用
         */
        template.setListeners(listeners);
        
        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {
                    
                    public String doWithRetry(RetryContext context) throws Exception {
                        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
                        int number = new Random().nextInt(10) + 1;
                        if (number > 5) {
                            
                            System.out.println("执行Buiness logic. NPE" + "开始执行时间:" + s.format(new Date()));
                            // 抛出异常
                            throw new NullPointerException("NullPointerException");
                        } else {
                            
                            System.out.println("执行Buiness logic. TE" + "开始执行时间:" + s.format(new Date()));
                            // 抛出异常
                            throw new TimeoutException("TimeoutException");
                        }
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                     // TODO 推送次数,推送完毕后,还没有成功,发送预警短信,通知人工处理
                        
                        return "FAIL";
                    }
                }
                );
        
        System.out.println(result);
    }
    
    
    
    @Test
    public void realRetryListenerTest() throws Exception{
        
        // Spring-retry提供了RetryOperations接口的实现类RetryTemplate
        RetryTemplate template = new RetryTemplate();
        
        // 简单重试策略
        SimpleRetryPolicy policy = new SimpleRetryPolicy(); // 默认重试3次
        // 设置重试策略
        template.setRetryPolicy(policy);
        
        // 固定时间退避策略
        FixedBackOffPolicy backOffPolicy1 = new FixedBackOffPolicy();
        backOffPolicy1.setBackOffPeriod(2000); // Default back off period - 1000ms.
        // 设置退避策略
        template.setBackOffPolicy(backOffPolicy1);
        // 监听器1
        RetryListener retryListener1 = new RetryListener() {
            
            @Override
            public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
                System.out.println("1-open");
                return true;
            }
            
            @Override
            public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
                    Throwable throwable) {
                System.out.println("1-onError");
                System.out.println("save FAIL notify info");
            }
            
            @Override
            public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
                    Throwable throwable) {
                if (context.getRetryCount() < NOTIFY_RETRY_TIMES) {
                    // TODO 表示没有到达重试次数 就成功了。在这儿入库,保存通知成功信息。
                    System.out.println("save SUCCESS notify info");
                }
                System.out.println("1-close" + "重试了" + context.getRetryCount() +"次");
            }
        };
        // 监听组
        RetryListener[] listeners = {retryListener1};
        template.setListeners(listeners);
        
        // 执行
        String result = template.execute(
                new RetryCallback<String, Exception>() {
                    
                    public String doWithRetry(RetryContext context) throws Exception {
                        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
                        int number = new Random().nextInt(10) + 1;
                        if (number > 5) {
                            
                            System.out.println("执行Buiness logic. NPE" + "开始执行时间:" + s.format(new Date()));
                            // 抛出异常
                            throw new NullPointerException("NullPointerException");
                        }
                        
                        return "SUCCESS";
                    }
                },
                // 当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
                new RecoveryCallback<String>() {
                    public String recover(RetryContext context) throws Exception {
                        
                       
                        
                        return "FAIL";
                    }
                }
            );
        
        System.out.println(result);
    }
}
           

tips:如有疑问,欢迎评论交流。