Spring重试在RestController中不起作用

标签 spring spring-retry

我正在尝试 Spring 重试,但遇到了一个奇怪的问题。当我在 Rest Controller 中的方法上使用重试注释时,重试不起作用。但是,如果我将该方法移至单独的服务类,它就可以工作。以下代码不起作用:

@RestController
public class HelloController {

    @RequestMapping(value = "/hello")
    public String hello() {
        return getInfo();
    }

    @Retryable(RuntimeException.class)
    public String getInfo() {
        Random random = new Random();
        int r = random.nextInt(2);
        if (r == 1) {
            throw new RuntimeException();
        } else {
            return "Success";
        }
    }
}

但以下是:
@RestController
public class HelloController {

    @Autowired
    private SomeService service;

    @RequestMapping(value = "/hello")
    public String hello() {
        String result = service.getInfo();
        return result;
    }
}

@Service
public class SomeService {

    @Retryable(RuntimeException.class)
    public String getInfo() {
        Random random = new Random();
        int r = random.nextInt(2);
        if (r == 1) {
            throw new RuntimeException();
        } else {
            return "Success";
        }
    }
}

我的问题是为什么 @Retryable在 Controller 中使用时不工作?

最佳答案

您看到的问题是由于您如何调用 getInfo()方法。

在第一个示例中,您正在调用 getInfo()来自同一个 spring 管理的 bean。在第二个示例中,您正在调用 getInfo()来自不同的 Spring 管理 bean 。这种区别很微妙,但非常重要,很可能是导致您的问题的原因。

当您使用 @Retryable注解,Spring 正在围绕您的原始 bean 创建一个代理,以便它们可以在特殊情况下进行特殊处理。在这种特定情况下,Spring 应用一个 Advice 将调用委托(delegate)给您的实际方法,捕获 RuntimeException是它可能会抛出,并根据您的 @Retryable 的配置重试您的方法的调用注解。

此代理在您的情况下很重要的原因是只有外部调用者才能看到代理建议。您的 bean 不知道它被代理了,只知道它的方法正在被调用(通过代理建议)。当您的 bean 对其自身调用方法时,不涉及进一步的代理,这就是实际上不会发生重试的原因。

关于Spring重试在RestController中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36417493/

相关文章:

java - Spring 卡夫卡|如何使 DeserializationException 可重试?

java - NoSuchMethodException JacksonObjectMapperBuilderConfiguration

java - 如何使用 ThreadPoolTask​​Executor 获取线程状态?

java - 如何解决 "Error creating bean with name ' 步骤 2' defined in class path resource "异常

rabbitmq - 使用 spring-amqp 和 rabbitmq 实现带退避的非阻塞重试

spring - @Recover方法不会被@Retryable触发

java - 即使抛出 NullPointerException 后,Spring Batch 指数重试也不会启动

java - Thymeleaf + Spring Secucity -> #authentication 无法与另一个链接位置结合使用

spring - 如何修复此 FirebaseApp 名称 [DEFAULT] 已存在! spring-boot 和 firebase

spring - jetty 9 : No Spring WebApplicationInitializer types detected on classpath