从Spring调用具有Oauth2的API时,我们需要添加重试。

我们还没有想出如何轻松地做到这一点。我们甚至尝试使用拦截器,但没有运气。

这是我们的代码:

应用程序

@EnableRetry
@SpringBootApplication
public class Application {

    public static void main(String args[]) {
        SpringApplication.run(Application.class);
    }

    @Bean
    public OAuth2RestTemplate oAuth2RestTemplate(ClientHttpRequestInterceptor interceptor) {
        List<String> scopes = new ArrayList<>();
        scopes.add("some-scope");

        ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
        resourceDetails.setAccessTokenUri("tokenUrl");
        resourceDetails.setClientId("client-id");
        resourceDetails.setClientSecret("client-secret");
        resourceDetails.setScope(scopes);

        OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resourceDetails);

        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
        interceptors.add(interceptor);
        oAuth2RestTemplate.setInterceptors(interceptors);
        return oAuth2RestTemplate;
    }

    @Bean
    public CommandLineRunner run(OAuth2RestTemplate oAuth2RestTemplate) throws Exception {
        return args -> {
            oAuth2RestTemplate.getForObject(
                    "some-url-that-returns-error.com", Quote.class);
        };
    }
}


MyInterceptor.java

@Component
public class MyInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution execution) throws IOException {
        return interceptWithRetry(httpRequest, bytes, execution);
    }

    @Retryable
    private ClientHttpResponse interceptWithRetry(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution execution) throws IOException {
        System.out.println("====================================");
        return execution.execute(httpRequest, bytes);
    }
}


还有我们pom.xml中的依赖项

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


当我们运行此命令并且出现错误时,无论传递给@Retryable的参数如何,都看不到调用beign重试,拦截器仅被调用一次。

有人可以为此提供一些指导吗?

谢谢

最佳答案

我们仍然不知道Retryable在拦截器中不起作用的原因。我们最终将注释移动到Service中的方法,并完全摆脱了拦截器。

SomeService.java

@Service
public class SomeService {

    private OAuth2RestTemplate restTemplate;

    public SomeService(OAuth2RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Retryable
    public Quote getSomething() {
        System.out.println("============= THIS WILL THROW AN EXCEPTION =================");
        return restTemplate.getForObject(
                "some-url-that-returns-error.com", Quote.class);
    }

}


这可行。但是,最好避免在每种服务的每种方法上重复@Retryable(params)

现在,我会将问题标记为已回答。

10-05 23:29