@HttpExchange 是什么
@HttpExchange 是springboot3提供的声明式发送HTTP请求客户端工具。
使用
第一步:根据第三方服务的接口声明
假如有第三方接口api:http://localhost:8080/api/hello/{id}?name={name},返回String类型。
按照上面的格式,创建第三方Client接口:
java
@HttpExchange("/api/hello")
public interface ThirdClient {
@GetExchange("/{id}")
String sayHello(@PathVariable("id") int id,
@RequestParam(value = "name", defaultValue = "World") String name
);
// 也可以返回 ResponseEntity, 如果想要获取响应其他信息的话
// @GetExchange("/{id}")
// ResponseEntity<String> sayHello(@PathVariable("id") int id,
// @RequestParam(value = "name", defaultValue = "World") String name
// );
}
第二步:注入实现类
java
@Configuration
public class HttpExchangeConfig {
@Bean
public ThirdClient thirdClient(RestClient.Builder builder) {
RestClient restClient = builder
.baseUrl("http://localhost:8080")
.build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builderFor(RestClientAdapter.create(restClient))
.build();
return factory.createClient(ThirdClient.class);
}
}
第三步:调用
java
@Autowired
private ThirdClient thirdClient;
String s = thirdClient.sayHello(1, "aaa");
异常处理
本质上还是引用了RestClient发送请求,所以异常还是和RestClient异常一样。
通用异常是 RestClientException
4xx异常:HttpClientErrorException
5xx异常:HttpServerErrorException
网络错误:ResourceAccessException
重试
可以结合 spring retry 注解达到重试的效果
java
@HttpExchange("/api/hello")
public interface ThirdClient {
@GetExchange("/{id}")
@Retryable(retryFor = {RestClientException.class}, noRetryFor = {HttpClientErrorException.class}, maxAttempts = 3, backoff = @Backoff(delay = 5000), listeners = {"customRetryListener"})
ResponseEntity<String> sayHello(@PathVariable("id") int id, @RequestParam(value = "name", defaultValue = "World") String name);
}
这里还注入了一个自定义重试监听器,当执行重试操作的时候,可以打印一些自定义日志。
java
@Component
public class CustomRetryListener implements RetryListener {
private static final Logger log = LoggerFactory.getLogger(CustomRetryListener.class);
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
// 第一次调用前触发
log.info("开始重试操作 - 方法: {}", context.getAttribute(RetryContext.NAME));
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
// 最后一次重试结束后触发(无论成功失败)
if (throwable != null) {
log.error("重试结束,最终失败 - 方法: {}, 异常: {}", context.getAttribute(RetryContext.NAME), throwable.toString());
} else {
log.info("重试结束,成功 - 方法: {}, 重试次数: {}", context.getAttribute(RetryContext.NAME), context.getRetryCount());
}
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
// 每次重试失败后触发
log.warn("重试失败 - 方法: {}, 第 {} 次重试, 异常: {}",
context.getAttribute(RetryContext.NAME),
context.getRetryCount(),
throwable.toString());
}
}