Spring Boot 集成第三方 API 时,常见的超时与重试机制设计
在日常的Spring Boot开发中,经常需要和第三方系统进行交互,比如支付接口、短信接口、地图接口等等。
然而,第三方 API 并不是一直都稳定可用的。网络波动、服务异常、接口限流、超时未响应等情况非常常见。如果没有合理的超时与重试机制,可能导致:
- 请求长时间阻塞,拖垮线程池;
- 接口调用失败,直接返回错误,用户体验不佳;
- 在支付、下单等场景中,可能出现数据不一致的问题。
本文将结合 Spring Boot 常见的 HTTP 客户端(RestTemplate、WebClient、OpenFeign),系统性地讲解如何设置 超时与重试机制,并设计一套健壮的调用方案。
1. 常见 HTTP 客户端的超时配置
1.1. 使用 RestTemplate
- 配置类
@Configuration
public class RestTemplateConfig {@Beanpublic RestTemplate restTemplate(RestTemplateBuilder builder) {return builder.setConnectTimeout(Duration.ofSeconds(5)).setReadTimeout(Duration.ofSeconds(5)).build();}
}
- 使用示例
@RestController
@RequestMapping("demo")
public class DemoController {@Autowiredprivate RestTemplate restTemplate;@PostMapping("/getData1")public String getData1() {String url = "https://blog.csdn.net/weixin_54009596/article/details/151334355";return restTemplate.getForObject(url, String.class);//return restTemplate.getForEntity(url, String.class).getBody();}
}
1.2. 使用 WebClient
WebClient 是 Spring WebFlux 的非阻塞式 HTTP 客户端,比 RestTemplate 更加现代和灵活。
- 配置类
@Configuration
public class WebClientConfig {@Beanpublic WebClient webClient(WebClient.Builder builder) {return builder// 配置了baseUrl,默认读取这个.baseUrl("https://blog.csdn.net/weixin_54009596/article/details/151334355").clientConnector(new ReactorClientHttpConnector(HttpClient.create().responseTimeout(Duration.ofSeconds(10)) // 响应超时.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) // 连接超时)).build();}
}
- 使用示例
@RestController
@RequestMapping("demo")
public class DemoController {@Autowiredprivate WebClient webClient;@PostMapping("/getData2")public Mono<String> getData2() {return webClient.get().uri("/151334355") //拼上配置中的url.retrieve().bodyToMono(String.class);}
}
WebClient 在高并发场景下比 RestTemplate 更有优势。
1.3. 使用 OpenFeign
- 配置超时
feign:client:config:default:connectTimeout: 5000 # 连接超时readTimeout: 10000 # 读取超时
- 使用示例
@FeignClient(name = "thirdApi", url = "https://blog.csdn.net/weixin_54009596/article/details/151334355")
public interface ThirdPartyClient {@GetMapping("/data")String getData();
}
2. 重试机制设计
2.1. 使用 Spring Retry
Spring 提供了 spring-retry 组件,可以优雅地实现重试。
- 引入依赖
<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId>
</dependency>
-
启动类上加
@EnableRetry
注解 -
使用
@Service
@Slf4j
public class DemoService {@Autowiredprivate RestTemplate restTemplate;@Retryable(value = { SocketTimeoutException.class, IOException.class },maxAttempts = 3, backoff = @Backoff(delay = 10000, multiplier = 2))public String getData1() {String url = "https://blog.csdn.net/weixin_54009596/article/details/151334355";try {return restTemplate.getForEntity(url, String.class).getBody();} catch (Exception e) {return recover(e);}}@Recoverpublic String recover(Exception e) {log.error("调用失败,进入降级逻辑1: {}", e.getMessage());return"fallback response";}
}
说明:
@Retryable:指定异常重试,最大尝试次数,延迟时间;
@Backoff:支持指数退避,避免短时间内的频繁请求;
@Recover:定义最终失败时的降级逻辑。
2.2. 使用 Resilience4j 实现重试 + 熔断
更强大的选择是 Resilience4j,支持 重试、熔断、限流、隔离舱。
- 引入依赖
<dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-spring-boot2</artifactId><version>1.7.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
- 配置
resilience4j.retry:instances:apiRetry:max-attempts: 3wait-duration: 2sretry-exceptions:- java.io.IOException- java.net.SocketTimeoutException
- 使用
@Service
@Slf4j
public class DemoService {@Autowiredprivate RestTemplate restTemplate;@Retry(name = "apiRetry", fallbackMethod = "fallback")public String getData1() {String url = "https://blog.csdn.net/weixin_54009596/article/details/151334355";return restTemplate.getForEntity(url, String.class).getBody();}public String fallback(Exception e) {log.error("调用失败,进入降级逻辑2: {}", e.getMessage());return"fallback response";}
}