Spring重试在RestController中不起作用

fal*_*con 6 spring spring-retry

我正在尝试弹簧重试,我面临一个奇怪的问题.当我在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";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但以下是:

@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";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么@Retryable在控制器中使用时不起作用?

nic*_*ild 15

您看到的问题是由于您调用getInfo()方法的方式.

在第一个示例中,您getInfo()从同一个Spring托管bean 中调用.在第二个示例中,您getInfo()从另一个Spring托管bean 调用.这种区别很微妙,但非常重要,很可能是导致问题的原因.

当您使用@Retryable注释时,Spring会在原始bean周围创建一个代理,以便他们可以在特殊情况下进行特殊处理.在这种特定情况下,Spring应用一个建议,它将委托一个调用实际方法,捕获RuntimeException它可能抛出的方法,并根据@Retryable注释的配置重试方法的调用.

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