Spring @Retryable - 调用时如何记录?
Spring @Retryable - how to log when it is invoked?
我用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(){...}
重试时如何输出一些特定的信息?
查看代码,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
如果您想记录特定的异常,您可以捕获异常记录并重新抛出。不幸的是,据我所知,没有办法在框架内记录自定义消息。
另一种方法是隐藏负责调用您的方法的实际拦截器,例如 RetryOperationsInterceptor
,但不建议这样做。
您可以注册一个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"));
}
});
如果您不需要从所有 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());
}
});
}
我用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(){...}
重试时如何输出一些特定的信息?
查看代码,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
如果您想记录特定的异常,您可以捕获异常记录并重新抛出。不幸的是,据我所知,没有办法在框架内记录自定义消息。
另一种方法是隐藏负责调用您的方法的实际拦截器,例如 RetryOperationsInterceptor
,但不建议这样做。
您可以注册一个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"));
}
});
如果您不需要从所有 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());
}
});
}