SpringBoot中如何测量RestTemplate同步及异步调用的响应时间?
测量SpringBoot中外部API调用的响应耗时
一、RestTemplate同步调用的耗时测量
1. 手动计时(快速实现)
在调用前后直接记录时间戳,计算差值即可,适合单个方法的快速测试:
public void execute(Request request) { long startTime = System.currentTimeMillis(); try { this.restTemplate.postForObject(System.getenv("URL"), request, String.class); } finally { long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("同步API调用耗时: " + elapsedTime + "ms"); // 可将耗时数据上报至监控系统或写入日志 } }
2. 全局拦截器(统一管控)
实现ClientHttpRequestInterceptor接口,对所有RestTemplate调用统一计时,无需在每个方法中重复编写代码:
@Component public class ApiTimingInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { long startTime = System.currentTimeMillis(); ClientHttpResponse response = execution.execute(request, body); long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("请求URL: " + request.getURI() + " | 响应耗时: " + elapsedTime + "ms"); return response; } }
将拦截器注入RestTemplate:
@Bean public RestTemplate restTemplate(ApiTimingInterceptor timingInterceptor) { RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add(timingInterceptor); return restTemplate; }
二、RestTemplate异步调用的耗时测量
RestTemplate本身没有原生异步方法,但可以通过两种方式实现异步调用并计时:
1. 结合Spring异步注解@Async
先配置异步线程池:
@Configuration @EnableAsync public class AsyncPoolConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.initialize(); return executor; } }
在异步方法中添加计时逻辑:
@Async public CompletableFuture<Void> executeAsync(Request request) { long startTime = System.currentTimeMillis(); try { this.restTemplate.postForObject(System.getenv("URL"), request, String.class); long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("异步API调用耗时: " + elapsedTime + "ms"); return CompletableFuture.completedFuture(null); } catch (Exception e) { long elapsedTime = System.currentTimeMillis() - startTime; System.err.println("异步API调用失败,耗时: " + elapsedTime + "ms | 错误信息: " + e.getMessage()); return CompletableFuture.failedFuture(e); } }
2. 使用AsyncRestTemplate(注意:Spring 5后已过时,推荐用WebClient)
@Bean public AsyncRestTemplate asyncRestTemplate(ApiTimingInterceptor timingInterceptor) { AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(); asyncRestTemplate.getInterceptors().add(timingInterceptor); return asyncRestTemplate; } public void executeAsyncWithAsyncRestTemplate(Request request) { ListenableFuture<ResponseEntity<String>> future = asyncRestTemplate.postForEntity(System.getenv("URL"), request, String.class); future.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() { private final long startTime = System.currentTimeMillis(); @Override public void onSuccess(ResponseEntity<String> result) { long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("AsyncRestTemplate调用耗时: " + elapsedTime + "ms"); } @Override public void onFailure(Throwable ex) { long elapsedTime = System.currentTimeMillis() - startTime; System.err.println("AsyncRestTemplate调用失败,耗时: " + elapsedTime + "ms"); } }); }
三、其他REST调用框架的耗时测量方案
1. WebClient(Spring 5+推荐的异步非阻塞框架)
WebClient支持链式调用,可通过doOnSuccess和doOnError回调记录耗时:
@Bean public WebClient webClient() { return WebClient.builder().build(); } public Mono<Void> executeWithWebClient(Request request) { long startTime = System.currentTimeMillis(); return webClient.post() .uri(System.getenv("URL")) .bodyValue(request) .retrieve() .bodyToMono(String.class) .doOnSuccess(response -> { long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("WebClient调用耗时: " + elapsedTime + "ms"); }) .doOnError(error -> { long elapsedTime = System.currentTimeMillis() - startTime; System.err.println("WebClient调用失败,耗时: " + elapsedTime + "ms"); }) .then(); }
2. OkHttp
通过添加全局Interceptor实现统一计时:
@Bean public OkHttpClient okHttpClient() { return new OkHttpClient.Builder() .addInterceptor(chain -> { long startTime = System.currentTimeMillis(); Response response = chain.proceed(chain.request()); long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("OkHttp请求URL: " + chain.request().url() + " | 耗时: " + elapsedTime + "ms"); return response; }) .build(); } // 调用示例 public void executeWithOkHttp(Request request) throws IOException { OkHttpClient client = okHttpClient(); RequestBody body = RequestBody.create( new Gson().toJson(request), MediaType.parse("application/json") ); Request okRequest = new Request.Builder() .url(System.getenv("URL")) .post(body) .build(); try (Response response = client.newCall(okRequest).execute()) { // 处理响应逻辑 } }
内容的提问来源于stack exchange,提问作者Italo Vieira
相关产品推荐
相关产品推荐

