为什么@PostConstruct 和@Retryable 不能一起使用?

Why can't @PostConstruct and @Retryable be used together?

我使用 AnnotationConfigApplicationContext 创建了一个基于 spring 框架的应用程序。

一个 bean 有一个 init 方法,它创建到外部服务的连接。这可以在 bean 启动后自动用 @PostConstruct 注释到 运行。

为了在创建此连接时处理任何异常,我希望我的 init 方法在捕获到异常时最多重试 5 次。当用 @PostConstruct@Retryable 注释方法时,我看到异常被抛出一次并且程序退出 - 看起来 @Retryable 没有效果。

我在配置 class 中正确使用了 @EnableRetry 以及 @Configuration。我在同一个 bean 上创建了另一个方法 B,它被注释为可重试,如果在实例化 bean 之后调用此方法,我可以看到该方法在抛出异常时按预期获得 retried/behaves。

我关于为什么这不起作用的想法可能与某些方面相关,或者后构造发生在 spring-retry 元素被附加之前?

实际上是否有更好的方法来拥有可以处理异常并可通过注释重试的初始化方法,而不是在方法中以编程方式尝试?

编辑:我现在同意不应通过 @Postconstruct 创建与外部服务的连接。如果重试失败可能会产生不利影响,这可以阻止整个上下文初始化。

然而,这还没有回答 Spring 框架的哪一部分不允许这两个注释一起工作的问题。

我建议您实际应用一个 ApplicationListener 来侦听 ContextRefreshedEvent 并用您的重试逻辑注释此方法。一旦上下文完全刷新并且所有 bean 都已正确配置和连接,就会触发这些侦听器。

To handle any exceptions when creating this connection I want my init method to retry up to 5 times if an exception is caught.

永远不要在 init 方法中连接到资源;您应该先等待上下文创建。

实施 SmartLifecycle 并在 start() 中连接要好得多。这样,您可以确保在开始连接到外部资源之前已经初始化了整个上下文。

这样,start() 方法应该被重试拦截器告知。

正如@Naros 所建议的那样,ContextRefreshedEvent 是另一种选择,但你应该,永远,永远不要在 @PostConstruct 中做那样的事情。

'@Retryable' 是 'spring-retry' 应用的方面。这仅在完全创建 spring 上下文之后附加,毕竟这是所有带“@PostConstruct”注释的方法 运行 因此“@Retryable”无效。