You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MethodInvocationRetryListenerSupport中获取类级@Retryable的label?

解决Spring Retry类级别@Retryable的label获取问题

问题原因

当使用**自定义RetryOperationsInterceptor**时,类级别@Retryable注解的label属性不会自动传递到MethodInvocationRetryCallback中,默认情况下getLabel()返回的是方法签名,而非注解配置的label值。

解决方案

通过MethodInvocationRetryCallback获取目标方法所在的类,再通过反射读取类级别(或方法级别)的@Retryable注解中的label值。修改GrpcClientRetryListener的相关方法如下:

@Slf4j
@Component
public class GrpcClientRetryListener extends MethodInvocationRetryListenerSupport {

    @Override
    public <T, E extends Throwable> void onSuccess(
            RetryContext context, RetryCallback<T, E> callback, T result) {
        if (callback instanceof MethodInvocationRetryCallback<T, E> methodInvocationRetryCallback) {
            log.info(
                    "重试成功: {}, 重试次数: {}",
                    getRetryLabel(methodInvocationRetryCallback),
                    context.getRetryCount());
        }
        super.onSuccess(context, callback, result);
    }

    @Override
    public <T, E extends Throwable> void onError(
            RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        if (callback instanceof MethodInvocationRetryCallback<T, E> methodInvocationRetryCallback) {
            log.info(
                    "重试失败: {}, 重试次数: {}",
                    getRetryLabel(methodInvocationRetryCallback),
                    context.getRetryCount());
        }
        super.onError(context, callback, throwable);
    }

    private <T, E extends Throwable> String getRetryLabel(
            MethodInvocationRetryCallback<T, E> methodInvocationRetryCallback) {
        MethodInvocation invocation = methodInvocationRetryCallback.getInvocation();
        // 获取目标类实例的Class对象
        Class<?> targetClass = invocation.getThis().getClass();
        
        // 优先读取方法上的@Retryable注解label
        Retryable methodRetryable = invocation.getMethod().getAnnotation(Retryable.class);
        if (methodRetryable != null && !StringUtils.isEmpty(methodRetryable.label())) {
            return methodRetryable.label();
        }
        
        // 读取类上的@Retryable注解label(处理代理类场景)
        Retryable classRetryable = AnnotationUtils.findAnnotation(targetClass, Retryable.class);
        if (classRetryable != null && !StringUtils.isEmpty(classRetryable.label())) {
            return classRetryable.label();
        }
        
        // 无配置时返回方法签名作为兜底
        return methodInvocationRetryCallback.getLabel();
    }
}

关键说明

  • 使用AnnotationUtils.findAnnotation而非直接targetClass.getAnnotation(),确保能正确获取代理类背后的真实类上的注解。
  • 遵循Spring Retry的注解优先级:方法级别注解优先于类级别注解,如果方法上配置了@Retryable,优先读取方法的label值。
  • 保留方法签名作为兜底逻辑,避免无注解场景下出现空值。

额外注意

无需修改GrpcClientRetryConfig中的拦截器配置,当前方案通过反射直接读取注解属性,不依赖拦截器的参数传递逻辑。

内容的提问来源于stack exchange,提问作者tuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 00:42:50