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

Spring Boot中双API数据处理性能优化方案咨询

性能优化方案

针对你遇到的Spring Boot应用串行调用API耗时过长、异步优化未达预期的问题,以下是几个可落地的优化方向:

1. 复用RestTemplate并配置HTTP连接池

每次调用新建RestTemplate是严重的性能浪费——RestTemplate本身是线程安全的,重复创建会导致TCP连接频繁建立/销毁,即使异步也会因为连接瓶颈拖慢速度。

解决方案:
创建全局单例的RestTemplate,并配置HttpClient连接池,复用TCP连接:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate() {
        HttpClient httpClient = HttpClientBuilder.create()
                .setMaxConnTotal(100) // 最大总连接数
                .setMaxConnPerRoute(50) // 每个域名的最大连接数
                .setConnectionTimeToLive(30, TimeUnit.SECONDS) // 连接存活时间
                .build();

        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
        factory.setConnectTimeout(5000); // 连接超时
        factory.setReadTimeout(5000); // 读取超时

        return new RestTemplate(factory);
    }
}

之后在getDescriptionFromSecondAPI中注入这个全局RestTemplate,不再每次新建。

2. 优化线程池配置

Executors.newFixedThreadPool(100)的问题在于:

  • 无界队列会导致任务堆积,线程数固定但连接池可能跟不上
  • 未针对IO密集型任务优化(HTTP请求属于IO密集型,线程数建议设置为CPU核心数 * 2 + 1,或根据连接池大小调整)

解决方案:
自定义ThreadPoolExecutor,配合连接池大小设置合理的线程数:

@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean(name = "apiExecutor")
    public Executor apiExecutor() {
        int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(50); // 结合连接池总连接数调整
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("api-async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略,避免任务丢失
        executor.initialize();
        return executor;
    }
}

然后在调用第二个API的方法上添加@Async("apiExecutor"),返回CompletableFuture<String>:

@Async("apiExecutor")
public CompletableFuture<String> getDescriptionFromSecondAPI(String id) {
    // 用注入的RestTemplate调用API
    String result = restTemplate.getForObject("xxx/api/desc/{id}", String.class, id);
    return CompletableFuture.completedFuture(result);
}

处理时批量收集Future并等待结果:

List<FirstAPIResult> firstResults = getFirstAPIResults();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (FirstAPIResult result : firstResults) {
    CompletableFuture<String> descFuture = getDescriptionFromSecondAPI(result.getId());
    CompletableFuture<Void> future = descFuture.thenAccept(desc -> result.setDescription(desc));
    futures.add(future);
}
// 等待所有异步任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

3. 尝试批量调用第二个API(如果支持)

如果第二个API提供批量查询接口,把所有需要查询的ID打包成一个请求,直接减少HTTP请求次数,这比并发单个请求效率提升更明显。

比如:

// 收集所有需要查询的ID
List<String> ids = firstResults.stream().map(FirstAPIResult::getId).collect(Collectors.toList());
// 调用批量API
Map<String, String> descMap = restTemplate.postForObject("xxx/api/desc/batch", ids, new ParameterizedTypeReference<Map<String, String>>() {});
// 批量设置描述
firstResults.forEach(result -> result.setDescription(descMap.get(result.getId())));

4. 增加缓存(如果数据允许)

如果第二个API返回的描述数据不会频繁变化,可以添加本地缓存(如Caffeine)或分布式缓存(如Redis),避免重复请求相同ID的数据:

@Cacheable(value = "apiDesc", key = "#id")
public String getDescriptionFromSecondAPI(String id) {
    return restTemplate.getForObject("xxx/api/desc/{id}", String.class, id);
}

内容的提问来源于stack exchange,提问作者Neelam Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 14:05:10