我正在尝试 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/