在Java Spring Boot中,你可以使用CompletableFuture
或者Spring的@Async
注解来实现并发调用多个API接口查询酒店数据。由于你提到使用线程池,并且线程数量不确定(但在这个特定场景中,你实际上只有三个线程,对应三个API调用),我们可以配置一个线程池,并使用它来执行这些任务。
以下是一个使用Spring Boot和CompletableFuture
结合线程池来实现这个需求的示例:
配置线程池:
在你的Spring Boot应用中,你可以配置一个线程池。这通常在配置类中进行。
java复制代码
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration public class AsyncConfig {
@Bean(name = "taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3); // 核心线程数 executor.setMaxPoolSize(5); // 最大线程数 executor.setQueueCapacity(100); // 队列容量 executor.setThreadNamePrefix("HotelFetcher-"); executor.initialize(); return executor; } }
创建服务类来调用API:
创建一个服务类,该类将使用CompletableFuture
来异步调用API,并使用前面配置的线程池来执行这些任务。
java复制代码
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate;
import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors;
@Service public class HotelService {
@Autowired private RestTemplate restTemplate;
@Async("taskExecutor") public CompletableFuture<List<Hotel>> fetchHotelsFromSource(String sourceUrl, String city, int limit) { // 假设每个API返回的是一个包含Hotel对象的JSON数组 String response = restTemplate.getForObject(sourceUrl + "?city=" + city + "&limit=" + limit, String.class); // 这里需要解析JSON响应为Hotel对象的列表 // 由于具体的解析逻辑取决于你的API响应格式,这里省略了详细实现 // 假设parseHotelsFromJson是一个解析JSON的方法 List<Hotel> hotels = parseHotelsFromJson(response); return CompletableFuture.completedFuture(hotels); }
// 假设的解析方法,你需要根据你的API响应格式来实现 private List<Hotel> parseHotelsFromJson(String json) { // 解析逻辑... return List.of(); // 返回一个示例空列表 }
// Hotel类应该包含你需要的字段,比如名称、地址等 // public class Hotel { /* 字段和getter/setter */ }
public List<Hotel> fetchTop10Hotels(String city) throws InterruptedException, ExecutionException { String[] sources = { "https://api.meituan.com/hotels", "https://api.ctrip.com/hotels", "https://api.business-travel.com/hotels" };
CompletableFuture<List<Hotel>>[] futures = new CompletableFuture[sources.length]; for (int i = 0; i < sources.length; i++) { futures[i] = fetchHotelsFromSource(sources[i], city, 10); // 每个API查询最多10家酒店 }
// 使用CompletableFuture.allOf等待所有任务完成 CompletableFuture.allOf(futures).join();
// 收集所有结果并合并为一个列表 List<Hotel> allHotels = Arrays.stream(futures) .map(future -> { try { return future.get(); // 获取每个CompletableFuture的结果 } catch (InterruptedException | ExecutionException e) { // 处理异常,这里简单地返回空列表,或者你可以抛出异常 return List.of(); } }) .flatMap(List::stream) // 将列表展平为一个流 .limit(10) // 限制结果为前10个 .collect(Collectors.toList()); // 收集为列表
return allHotels; } }
注意:
在上面的代码中,
parseHotelsFromJson
方法是一个占位符,你需要根据你的API响应格式来实现它。Hotel
类应该包含你需要的字段,比如名称、地址等,你需要根据你的需求来定义它。在
fetchTop10Hotels
方法中,我们使用了CompletableFuture.allOf
来等待所有任务完成,然后收集结果。由于我们想要前10家酒店,所以我们使用了stream().limit(10)
来限制结果的数量。但是请注意,如果某个API返回的结果很少,而其他API返回的结果很多,这种方法可能不会精确地返回“最好的”10家酒店(根据某种标准)。你可能需要实现更复杂的逻辑来选择前10家。由于
@Async
注解默认使用Spring的TaskExecutor
(如果你没有指定的话),我们通过@Async("taskExecutor")
来指定使用我们自定义的线程池。确保你的Spring Boot应用已经启用了异步支持,这通常通过在主类上添加
@EnableAsync
注解来实现。
0条评论
点击登录参与评论