Spring @Retryable - 如何在调用时记录?

Jus*_*tas 9 spring spring-retry spring-boot

我用compile 'org.springframework.retry:spring-retry:1.2.2.RELEASE'Spring Boot 1.5.9.RELEASE.

配置为重试我的方法,它运作良好:

@Retryable(value = { IOException.class }, maxAttempts = 5, backoff = @Backoff(delay = 500))
public void someMethod(){...}
Run Code Online (Sandbox Code Playgroud)

重试发生时如何输出某些特定消息?

whi*_*mot 17

你可以注册一个RetryListener:

@Bean
public List<RetryListener> retryListeners() {
    Logger log = LoggerFactory.getLogger(getClass());

    return Collections.singletonList(new RetryListener() {

        @Override
        public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
            // The 'context.name' attribute has not been set on the context yet. So we have to use reflection.
            Field labelField = ReflectionUtils.findField(callback.getClass(), "val$label");
            ReflectionUtils.makeAccessible(labelField);
            String label = (String) ReflectionUtils.getField(labelField, callback);
            log.trace("Starting retryable method {}", label);
            return true;
        }

        @Override
        public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
            log.warn("Retryable method {} threw {}th exception {}",
                    context.getAttribute("context.name"), context.getRetryCount(), throwable.toString());
        }

        @Override
        public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
            log.trace("Finished retryable method {}", context.getAttribute("context.name"));
        }
    });
Run Code Online (Sandbox Code Playgroud)

如果您不需要从所有3个拦截点进行记录,则可以覆盖RetryListenerSupport.例如:

@Bean
public List<RetryListener> retryListeners() {
    Logger log = LoggerFactory.getLogger(getClass());

    return Collections.singletonList(new RetryListenerSupport() {

        @Override
        public <T, E extends Throwable> void onError(
                RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
            log.warn("Retryable method {} threw {}th exception {}",
                    context.getAttribute("context.name"), 
                    context.getRetryCount(), throwable.toString());
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

  • 一旦我启用实现 RetryListenerSupport 的 bean,我的 @Retryable 注释方法就不再受到尊重。有任何想法吗? (3认同)
  • 这个特殊字符“val$label”是什么?这是Spring SpEL吗?( ReflectionUtils.findField(callback.getClass(), "val$label");) (2认同)

Kon*_*tin 6

查看代码org.springframework.retry.support.RetryTemplate执行重试逻辑以重试操作。这个模板只记录简单的事情,比如:

o.s.retry.support.RetryTemplate          : Retry: count=0
o.s.retry.support.RetryTemplate          : Checking for rethrow: count=1
o.s.retry.support.RetryTemplate          : Retry: count=1
o.s.retry.support.RetryTemplate          : Checking for rethrow: count=2
o.s.retry.support.RetryTemplate          : Retry: count=2
o.s.retry.support.RetryTemplate          : Checking for rethrow: count=3
o.s.retry.support.RetryTemplate          : Retry failed last attempt: count=3
Run Code Online (Sandbox Code Playgroud)

如果您想记录特定的异常,您可以捕获异常记录并重新抛出。不幸的是,据我所知,无法在框架内记录自定义消息。

另一种方法是隐藏负责调用您的方法的实际拦截器RetryOperationsInterceptor,但是不建议这样做。