Java 使用Spring重试指定特定于异常的回退策略

Java 使用Spring重试指定特定于异常的回退策略,java,spring,exception-handling,spring-retry,Java,Spring,Exception Handling,Spring Retry,我正在使用它进行一些数据库操作。在SQLRecoverableException上,我重试三次(这假设导致异常的任何原因如果失败三次都不是暂时的),在sqltransienteexception上,我无限期地重试(如果不访问数据库,程序将无法执行任何操作,因此它可能会继续重试,直到用户决定重新启动服务器),并且在任何其他异常情况下,我都不会重试。我使用指数退避策略,基本重试时间为100ms,最大重试时间为30000ms private static final int MAX_RECOVERAB

我正在使用它进行一些数据库操作。在
SQLRecoverableException
上,我重试三次(这假设导致异常的任何原因如果失败三次都不是暂时的),在
sqltransienteexception上,我无限期地重试(如果不访问数据库,程序将无法执行任何操作,因此它可能会继续重试,直到用户决定重新启动服务器),并且在任何其他异常情况下,我都不会重试。我使用指数退避策略,基本重试时间为100ms,最大重试时间为30000ms

private static final int MAX_RECOVERABLE_RETRIES = 3;
private static final long INITIAL_INTERVAL = 100;
private static final long MAX_INTERVAL = 30 * 1000;
private static final double MULTIPLIER = 2.0;

public static RetryTemplate databaseTemplate() {
    RetryTemplate template = new RetryTemplate();
    ExceptionClassifierRetryPolicy retryPolicy = new ExceptionClassifierRetryPolicy();
    Map<Class<? extends Throwable>, RetryPolicy> policyMap = new HashMap<>();
    NeverRetryPolicy baseException = new NeverRetryPolicy();
    SimpleRetryPolicy recoverablePolicy = new SimpleRetryPolicy();
    recoverablePolicy.setMaxAttempts(MAX_RECOVERABLE_RETRIES);
    AlwaysRetryPolicy transientPolicy = new AlwaysRetryPolicy();
    policyMap.put(Exception.class, baseException);
    policyMap.put(SQLRecoverableException.class, recoverablePolicy);
    policyMap.put(SQLTransientException.class, transientPolicy);
    retryPolicy.setPolicyMap(policyMap);
    template.setRetryPolicy(retryPolicy);
    ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
    backOffPolicy.setInitialInterval(INITIAL_INTERVAL);
    backOffPolicy.setMaxInterval(MAX_INTERVAL);
    backOffPolicy.setMultiplier(MULTIPLIER);
    template.setBackOffPolicy(backOffPolicy);
    return template;
}
private static final int MAX_RECOVERABLE_RETRIES=3;
专用静态最终长初始_间隔=100;
专用静态最终最大长间隔=30*1000;
专用静态最终双乘数=2.0;
公共静态RetryTemplate数据库模板(){
RetryTemplate=新RetryTemplate();
ExceptionClassifierRetryPolicy retryPolicy=新ExceptionClassifierRetryPolicy();

Map事实上,
例外classifierretrypolicy
是一条路要走。不过,我没有设法让它与
策略Map
一起工作

下面是我如何使用它的:

@Component("yourRetryPolicy")
public class YourRetryPolicy extends ExceptionClassifierRetryPolicy
{
    @PostConstruct
    public void init()
    {
        final SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
        simpleRetryPolicy.setMaxAttempts( 3 );

        this.setExceptionClassifier( new Classifier<Throwable, RetryPolicy>()
        {
            @Override
            public RetryPolicy classify( Throwable classifiable )
            {
                    if ( classifiable instanceof YourException )
                    {
                            return new NeverRetryPolicy();
                    }
                    // etc...
                    return simpleRetryPolicy;
            }
        });
    }
}

接受的答案只处理特定于异常的RetryPolicy实例。Spring不为特定于异常的BackOffPolicy实例提供任何现成的功能。 幸运的是,它很容易实现

import org.springframework.classify.Classifier
import org.springframework.classify.ClassifierSupport
import org.springframework.classify.SubclassClassifier
import org.springframework.retry.RetryContext
import org.springframework.retry.backoff.BackOffContext
import org.springframework.retry.backoff.BackOffInterruptedException
import org.springframework.retry.backoff.BackOffPolicy
import org.springframework.retry.backoff.NoBackOffPolicy

class ExceptionClassifierBackoffPolicy implements BackOffPolicy {

    private static class ExceptionClassifierBackoffContext implements BackOffContext, BackOffPolicy {
        Classifier<Throwable, BackOffPolicy> exceptionClassifier
        RetryContext retryContext
        Map<BackOffPolicy, BackOffContext> policyContextMap = [:]

        ExceptionClassifierBackoffContext(Classifier<Throwable, BackOffPolicy> exceptionClassifier, RetryContext retryContext) {
            this.exceptionClassifier = exceptionClassifier
            this.retryContext = retryContext
        }

        @Override
        BackOffContext start(RetryContext context) {
            return null
        }

        @Override
        void backOff(BackOffContext backOffContext) throws BackOffInterruptedException {
            def policy = exceptionClassifier.classify(retryContext.lastThrowable)
            def policyContext = policyContextMap.get(policy)
            if (!policyContext) {
                policyContext = policy.start(retryContext)
                policyContextMap.put(policy, policyContext)
            }
            policy.backOff(policyContext)
        }
    }
    private Classifier<Throwable, BackOffPolicy> exceptionClassifier = new ClassifierSupport<Throwable, BackOffPolicy>(new NoBackOffPolicy());

    void setPolicyMap(Map<Class<? extends Throwable>, BackOffPolicy> policyMap) {
        exceptionClassifier = new SubclassClassifier<Throwable, BackOffPolicy>(policyMap, new NoBackOffPolicy());
    }

    @Override
    BackOffContext start(RetryContext context) {
        return new ExceptionClassifierBackoffContext(exceptionClassifier, context)
    }

    @Override
    void backOff(BackOffContext backOffContext) throws BackOffInterruptedException {
        def classifierBackOffContext = (ExceptionClassifierBackoffContext) backOffContext
        classifierBackOffContext.backOff(backOffContext)
    }
}
import org.springframework.classify.Classifier
导入org.springframework.classify.ClassifierSupport
导入org.springframework.classify.SubassClassifier
导入org.springframework.retry.RetryContext
导入org.springframework.retry.backoff.BackOffContext
导入org.springframework.retry.backoff.backofInterruptedException
导入org.springframework.retry.backoff.BackOffPolicy
导入org.springframework.retry.backoff.NoBackOffPolicy
类异常ClassifierBackOffPolicy实现BackOffPolicy{
私有静态类ExceptionClassifierBackoffContext实现BackOffContext、BackOffPolicy{
分类器例外分类器
RetryContext RetryContext
Map policyContextMap=[:]
ExceptionClassifierBackoffContext(分类器exceptionClassifier,RetryContext RetryContext){
this.exceptionClassifier=exceptionClassifier
this.retryContext=retryContext
}
@凌驾
BackOffContext开始(RetryContext上下文){
返回空
}
@凌驾
void backOff(BackOffContext BackOffContext)抛出backoffinterruptedeexception{
def policy=exceptionClassifier.classify(retryContext.lastThrowable)
def policyContext=policyContextMap.get(策略)
如果(!policyContext){
policyContext=policy.start(retryContext)
policyContextMap.put(策略,policyContext)
}
policy.backOff(policyContext)
}
}
private Classifier exceptionClassifier=新分类器支持(new NoBackOffPolicy());

void setPolicyMap(Map到派对有点晚,但您所需要的只是根据不同的情况有不同的退避期 异常的类型,扩展
FixedBackoffPolicy
应该可以做到这一点,而且非常简单。 大致如下:

首先,创建回退策略类,该类接收带有 每个异常类型的退避期不同:

公共类MultipleExceptionBackoffPolicy扩展了FixedBackoffPolicy
{
私有分类器;

public MultipleExceptionsBackoffPolicy(最终映射)这有助于选择不同的
RetryPolicy
s,但OP希望选择不同的
BackOffPolicy
s。@Zim Zam O'Pootertoot这是您使用的吗?
import org.springframework.classify.Classifier
import org.springframework.classify.ClassifierSupport
import org.springframework.classify.SubclassClassifier
import org.springframework.retry.RetryContext
import org.springframework.retry.backoff.BackOffContext
import org.springframework.retry.backoff.BackOffInterruptedException
import org.springframework.retry.backoff.BackOffPolicy
import org.springframework.retry.backoff.NoBackOffPolicy

class ExceptionClassifierBackoffPolicy implements BackOffPolicy {

    private static class ExceptionClassifierBackoffContext implements BackOffContext, BackOffPolicy {
        Classifier<Throwable, BackOffPolicy> exceptionClassifier
        RetryContext retryContext
        Map<BackOffPolicy, BackOffContext> policyContextMap = [:]

        ExceptionClassifierBackoffContext(Classifier<Throwable, BackOffPolicy> exceptionClassifier, RetryContext retryContext) {
            this.exceptionClassifier = exceptionClassifier
            this.retryContext = retryContext
        }

        @Override
        BackOffContext start(RetryContext context) {
            return null
        }

        @Override
        void backOff(BackOffContext backOffContext) throws BackOffInterruptedException {
            def policy = exceptionClassifier.classify(retryContext.lastThrowable)
            def policyContext = policyContextMap.get(policy)
            if (!policyContext) {
                policyContext = policy.start(retryContext)
                policyContextMap.put(policy, policyContext)
            }
            policy.backOff(policyContext)
        }
    }
    private Classifier<Throwable, BackOffPolicy> exceptionClassifier = new ClassifierSupport<Throwable, BackOffPolicy>(new NoBackOffPolicy());

    void setPolicyMap(Map<Class<? extends Throwable>, BackOffPolicy> policyMap) {
        exceptionClassifier = new SubclassClassifier<Throwable, BackOffPolicy>(policyMap, new NoBackOffPolicy());
    }

    @Override
    BackOffContext start(RetryContext context) {
        return new ExceptionClassifierBackoffContext(exceptionClassifier, context)
    }

    @Override
    void backOff(BackOffContext backOffContext) throws BackOffInterruptedException {
        def classifierBackOffContext = (ExceptionClassifierBackoffContext) backOffContext
        classifierBackOffContext.backOff(backOffContext)
    }
}
BackOffPolicy backOffPolicy = new ExceptionClassifierBackoffPolicy()
def policyMap = [
        (RuntimeException): new FixedBackOffPolicy(backOffPeriod: 1000),
        (IOException)     : new ExponentialRandomBackOffPolicy(initialInterval: 500, maxInterval: 360000, multiplier: 2)
] as Map<Class<? extends Throwable>, BackOffPolicy>
backOffPolicy.policyMap = backoffPolicyMap