【问题标题】:Spring Retry: How to make all methods of a @Bean retryable?Spring Retry:如何使@Bean 的所有方法都可重试?
【发布时间】:2022-01-05 13:46:13
【问题描述】:

我想创建一个第三方服务的@Bean,例如 Keycloak(或任何其他),它可能在任何给定时间都可以访问,也可能无法访问。此对象应重试生成的 Keycloak bean 的所有方法。

我尝试了以下方法:

@Configuration
@EnableRetry
class KeycloakBeanProvider() {

    @Bean
    @Retryable
    fun keycloak(oauth2ClientRegistration: ClientRegistration): Keycloak {
        return KeycloakBuilder.builder()
            .serverUrl(serverUrl)
            .realm(oauth2ClientRegistration.clientName)
            .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
            .clientId(oauth2ClientRegistration.clientId)
            .clientSecret(oauth2ClientRegistration.clientSecret)
            .build()
    }
}

但是这种方式只会重试 bean 创建,而不是对 bean 的实际方法调用。我知道@Retryable 可以在类级别上使用,但我不拥有Keycloak 类,所以我不能在那里添加它。

如何使生成的Keycloak bean 的方法可重试?

【问题讨论】:

    标签: spring spring-retry


    【解决方案1】:

    你必须用@Retryable注释Keycloak

    @SpringBootApplication
    @EnableRetry
    public class So70593939Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So70593939Application.class, args);
        }
    
        @Bean
        ApplicationRunner runner(Foo foo) {
            return args -> {
                foo.foo("called foo");
                foo.bar("called bar");
            };
        }
    
    }
    
    @Component
    @Retryable
    class Foo {
    
        public void foo(String in) {
            System.out.println("foo");
            throw new RuntimeException("test");
        }
    
        public void bar(String in) {
            System.out.println("bar");
            throw new RuntimeException("test");
        }
    
        @Recover
        public void recover(Exception ex, String in) {
            System.out.println(ex.getMessage() + ":" + in);
        }
    
    }
    
    foo
    foo
    foo
    test:called foo
    bar
    bar
    bar
    test:called bar
    

    如果您无法对类进行注释(例如,因为它来自另一个项目),则需要使用 RetryTemplate 来调用其方法,而不是使用基于注释的重试。

    【讨论】:

    • 我担心这一点。我可能只是将我需要的方法包装在一个服务中,然后使该类可重试。
    • 一个简单的解决方案是创建一个可重试的委托类,每个方法都委托给实际的Keycloak 方法。然后到处使用委托类。
    • 是的,这或多或少是我的意思。我也偶然发现了这个问题,Keycloak 对象本身用于某些操作会创建更多需要重试的服务对象。像keycloak.users().delete(id) 这样的东西。所以我可能会采用扩展的委托方法,其中我可以有一个可重试的方法deleteUser(id)。由于我只需要Keycloakoffers 方法的一小部分,我认为有一个单独的类来委派它是可以的。
    猜你喜欢
    • 2019-03-27
    • 2019-11-12
    • 2021-07-25
    • 2018-11-06
    • 2020-07-23
    • 1970-01-01
    • 1970-01-01
    • 2017-04-13
    • 1970-01-01
    相关资源
    最近更新 更多