sunytonyli
3/9/2018 - 3:22 AM

SpringRetry学习的代码片段

SpringRetry学习的代码片段

/*
 * Alipay.com Inc.
 * Copyright (c) 2004-2017 All Rights Reserved.
 */
package com.alipay.kris.other.springretry;

import java.util.Collections;
import java.util.Map;

import com.google.common.collect.Maps;
import org.springframework.classify.BinaryExceptionClassifier;
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.RetryState;
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.ThreadWaitSleeper;
import org.springframework.retry.backoff.UniformRandomBackOffPolicy;
import org.springframework.retry.policy.AlwaysRetryPolicy;
import org.springframework.retry.policy.CircuitBreakerRetryPolicy;
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.stats.DefaultStatisticsRepository;
import org.springframework.retry.stats.StatisticsListener;
import org.springframework.retry.support.DefaultRetryState;
import org.springframework.retry.support.RetryTemplate;

/**
 * @author gongzuo.zy
 * @version $Id: Study.java, v0.1 2017-05-14 23:13  gongzuo.zy Exp $
 */
public class Study {

    private static void backoff () {
        RetryTemplate template = new RetryTemplate();

        // 指数回退 initial + x*Times 指数递增
        ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
        exponentialBackOffPolicy.setInitialInterval(100);
        exponentialBackOffPolicy.setMaxInterval(1000);
        exponentialBackOffPolicy.setMultiplier(0.5);
        exponentialBackOffPolicy.setSleeper(new ThreadWaitSleeper());

        // 随机指数,用于解决惊群效应
        ExponentialRandomBackOffPolicy exponentialRandomBackOffPolicy = new ExponentialRandomBackOffPolicy();
        exponentialRandomBackOffPolicy.setInitialInterval(100);
        exponentialRandomBackOffPolicy.setMaxInterval(1000);
        exponentialRandomBackOffPolicy.setMultiplier(0.5);
        exponentialBackOffPolicy.setSleeper(new ThreadWaitSleeper());

        // 不回避
        NoBackOffPolicy noBackOffPolicy = new NoBackOffPolicy();

        // 固定时间休眠
        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(1000L);
        fixedBackOffPolicy.setSleeper(new ThreadWaitSleeper());

        // 随机sleep一段时间,这个时间【from, to】可以指定
        UniformRandomBackOffPolicy uniformRandomBackOffPolicy  = new UniformRandomBackOffPolicy();
        uniformRandomBackOffPolicy.setMinBackOffPeriod(100);
        uniformRandomBackOffPolicy.setMaxBackOffPeriod(1000);
        uniformRandomBackOffPolicy.setSleeper(new ThreadWaitSleeper());

        template.setBackOffPolicy(uniformRandomBackOffPolicy);
    }

    private static void circuitBreakerRetryPolicy() throws Throwable {
        RetryTemplate template = new RetryTemplate();

        SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
        simpleRetryPolicy.setMaxAttempts(10);


        CircuitBreakerRetryPolicy circuitBreakerRetryPolicy = new CircuitBreakerRetryPolicy(simpleRetryPolicy);
        circuitBreakerRetryPolicy.setOpenTimeout(1000L);
        circuitBreakerRetryPolicy.setResetTimeout(2000L);

        template.setRetryPolicy(circuitBreakerRetryPolicy);
        execute(template);
    }

    // 顺序执行重试策略
    private static void compositeRetryPolicy() {
        CompositeRetryPolicy compositeRetryPolicy = new CompositeRetryPolicy();
        compositeRetryPolicy.setPolicies(new RetryPolicy[]{});

        // 乐观的意思是,默认不需要重试,有策略要重试的时候,才进行重试
        // 悲观的意思是,默认就需要重试,有策略不用重试的时候,就不进行重试
        compositeRetryPolicy.setOptimistic(true);
    }

    // 根据不同的异常,我们放入不同的retry机制,按照异常下发,常用
    private static void exceptionClassifierRetryPolicy () {
        ExceptionClassifierRetryPolicy exceptionClassifierRetryPolicy = new ExceptionClassifierRetryPolicy();

        Map<Class<? extends Throwable>, RetryPolicy> map = Maps.newHashMap();
        map.put(RuntimeException.class, new AlwaysRetryPolicy());
        exceptionClassifierRetryPolicy.setPolicyMap(map);
    }

    // 重试次数,常用
    private static void simpleRetryPolicy() throws Throwable {
        RetryTemplate template = new RetryTemplate();
        SimpleRetryPolicy alwaysRetryPolicy = new SimpleRetryPolicy();
        alwaysRetryPolicy.setMaxAttempts(5);
        template.setRetryPolicy(alwaysRetryPolicy);
        executeStateful(template);
    }

    // 永不重试,不推荐
    private static void neverRetryPolicy () throws Throwable {
        NeverRetryPolicy neverRetryPolicy = new NeverRetryPolicy();
        RetryTemplate template = new RetryTemplate();
        template.setRetryPolicy(neverRetryPolicy);
        execute(template);
    }

    // 永远重试,不推荐
    private static void alwaysRetryPolicy () throws Throwable {
        AlwaysRetryPolicy alwaysRetryPolicy = new AlwaysRetryPolicy();
        RetryTemplate template = new RetryTemplate();
        template.setRetryPolicy(alwaysRetryPolicy);
        execute(template);
    }

    private static void TimeoutRetryPolicy() throws Throwable {
        // 重试一秒,不断重试,1S后就不重试了
        RetryTemplate template = new RetryTemplate();
        TimeoutRetryPolicy policy = new TimeoutRetryPolicy();
        policy.setTimeout(10L);
        template.setRetryPolicy(policy);
        execute(template);
    }

    public static void main(String[] args) throws Throwable {
        // 新建一个模板,可用作为我一个spring bean注入进来
        RetryTemplate template = new RetryTemplate();

        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(20);

        template.setBackOffPolicy(backOffPolicy);
        template.setRetryPolicy(new SimpleRetryPolicy(5));

        // 执行模板
        template.execute(context -> remoteInvoke(), context -> {System.out.println("log here"); return "recovery";});
    }

    private static void execute(RetryTemplate template) throws Throwable {
        RetryListener listener = new RetryListener( ){
            @Override
            public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
                // 第一次重试的时候会执行该方法
                return true;
            }

            @Override
            public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
                                                       Throwable throwable) {
                // 重试结束后会调用改方法
            }

            @Override
            public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
                                                         Throwable throwable) {
                // 每次重试产生异常时会调用改方法
            }
        };

        DefaultStatisticsRepository defaultStatisticsRepository = new DefaultStatisticsRepository();
        StatisticsListener statisticsListener = new StatisticsListener(defaultStatisticsRepository);

        RetryListener[] listeners = new RetryListener[] {listener, statisticsListener};

        template.setListeners(listeners);

        String result = template.execute((RetryCallback<String, Throwable>)context -> {
            // 可以根据不同的异常来决定是否需要重试
            // 上下文有以下几个作用
            // 1, 能够得到上次的异常信息
            // 2, 能够得到当前的重试次数
            // 3, 可以将上次重试的参数放到map中(attribute)本次重试可以获得相关参数
            System.out.println(context.getAttribute("k"));
            context.setAttribute("k", times);
            remoteInvoke();
            return "ret";
        }, context -> {
            // 这里是出现异常的recovery策略
            System.out.println("recover");
            return "recovery";
        });

    }

    private static void executeStateful(RetryTemplate template) throws Throwable {

        BinaryExceptionClassifier classifier = new BinaryExceptionClassifier(
            Collections.singleton(Throwable.class)
        );

        RetryState state = new DefaultRetryState("mykey", false, classifier);

        // 有状态
        String result = template.execute((RetryCallback<String, Throwable>)context -> {
           // System.out.println(Thread.currentThread().getName());
            remoteInvoke();
            return "ret";
        }, context -> {
            // 这里是出现异常的recovery策略
            System.out.println("recover");
            return "recovery";
        }, state);
    }

    private static int times = 0;

    private static String remoteInvoke() {
        System.out.println("invoke:" + times++);
        throw new RuntimeException();
    }
}