You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 11:15:37