Java 同时调用多个Spring微服务URL
我有一个Spring引导应用程序,它将使用Java 同时调用多个Spring微服务URL,java,spring,multithreading,spring-boot,spring-webflux,Java,Spring,Multithreading,Spring Boot,Spring Webflux,我有一个Spring引导应用程序,它将使用GET方法调用几个微服务URL。这些微服务URL端点都实现为@RestControllers。它们不会返回Flux或Mono 我需要我的应用程序捕获哪些URL不是返回2xx HTTP状态的 我目前正在使用以下代码执行此操作: List<String> failedServiceUrls = new ArrayList<>(); for (String serviceUrl : serviceUrls.getServ
GET
方法调用几个微服务URL。这些微服务URL端点都实现为@RestController
s。它们不会返回Flux
或Mono
我需要我的应用程序捕获哪些URL不是返回2xx HTTP状态的
我目前正在使用以下代码执行此操作:
List<String> failedServiceUrls = new ArrayList<>();
for (String serviceUrl : serviceUrls.getServiceUrls()) {
try {
ResponseEntity<String> response = rest.getForEntity(serviceUrl, String.class);
if (!response.getStatusCode().is2xxSuccessful()) {
failedServiceUrls.add(serviceUrl);
}
} catch (Exception e){
failedServiceUrls.add(serviceUrl);
}
}
// all checks are complete so send email with the failedServiceUrls.
mail.sendEmail("Service Check Complete", failedServiceUrls);
}
List failedServiceUrls=new ArrayList();
for(字符串serviceUrl:serviceUrl.getserviceURL()){
试一试{
ResponseEntity response=rest.getForEntity(serviceUrl,String.class);
如果(!response.getStatusCode().is2xxSuccessful()){
failedServiceUrls.add(serviceUrl);
}
}捕获(例外e){
failedServiceUrls.add(serviceUrl);
}
}
//所有检查都已完成,请发送包含FailedServiceURL的电子邮件。
mail.sendmail(“服务检查完成”,失败的服务URL);
}
问题是每个URL调用的响应速度都很慢,我必须等待一个URL调用完成,然后再进行下一个URL调用
如何更改此设置以使URL调用同时进行?在所有呼叫完成后,我需要发送一封电子邮件,其中包含应在failedServiceUrls
中收集的错误URL
更新
我修改了上面的帖子,说我只想同时打电话。我不在乎rest.getForEntity调用阻塞。如果您只想同时进行调用,而不在乎阻塞线程,您可以:
Mono#fromCallable
Flux#fromIterable
Flux#filter同时调用和筛选失败的服务。和来自1的异步服务调用
Flux\collectList
等待所有呼叫完成,然后在subscribe
void sendFailedUrls(){
Flux.fromIterable(ServiceUrls.getServiceUrls())
.filterWhen(url->responseFailed(url))
.LIST()
.subscribe(failedURls->mail.sendmail(“服务检查完成”,failedURls));
}
单响应(字符串url){
返回Mono.fromCallable(()->rest.getForEntity(url,String.class))
.map(response->!response.getStatusCode().is2xxsuccesful())
.subscribeOn(Schedulers.boundedElastic());
}
用Reactor阻塞呼叫
由于底层服务调用正在阻塞,因此应该在专用线程池上执行。如果要实现完全并发,此线程池的大小应等于并发调用的数量。这就是为什么我们需要.subscribeOn(Schedulers.boundedElastic())
见:
使用WebClient的更好解决方案
但是请注意,在使用reactor和springwebflux时,应该避免阻塞调用。正确的方法是将Spring 5中的RestTemplate
替换为WebClient
,它是完全非阻塞的
请参阅:如果您只想同时进行调用,而不关心阻塞线程,则可以:
Mono#fromCallable
Flux#fromIterable
Flux#filter同时调用和筛选失败的服务。和来自1的异步服务调用
Flux\collectList
等待所有呼叫完成,然后在subscribe
void sendFailedUrls(){
Flux.fromIterable(ServiceUrls.getServiceUrls())
.filterWhen(url->responseFailed(url))
.LIST()
.subscribe(failedURls->mail.sendmail(“服务检查完成”,failedURls));
}
单响应(字符串url){
返回Mono.fromCallable(()->rest.getForEntity(url,String.class))
.map(response->!response.getStatusCode().is2xxsuccesful())
.subscribeOn(Schedulers.boundedElastic());
}
用Reactor阻塞呼叫
由于底层服务调用正在阻塞,因此应该在专用线程池上执行。如果要实现完全并发,此线程池的大小应等于并发调用的数量。这就是为什么我们需要.subscribeOn(Schedulers.boundedElastic())
见:
使用WebClient的更好解决方案
但是请注意,在使用reactor和springwebflux时,应该避免阻塞调用。正确的方法是将Spring 5中的RestTemplate
替换为WebClient
,它是完全非阻塞的
请参阅:使用代码中的executor服务,可以通过以下方式并行调用所有微服务:
// synchronised it as per Maciej's comment:
failedServiceUrls = Collections.synchronizedList(failedServiceUrls);
ExecutorService executorService = Executors.newFixedThreadPool(serviceUrls.getServiceUrls().size());
List<Callable<String>> runnables = new ArrayList<>().stream().map(o -> new Callable<String>() {
@Override
public String call() throws Exception {
ResponseEntity<String> response = rest.getForEntity(serviceUrl, String.class);
// do something with the response
if (!response.getStatusCode().is2xxSuccessful()) {
failedServiceUrls.add(serviceUrl);
}
return response.getBody();
}
}).collect(toList());
List<Future<String>> result = executorService.invokeAll(runnables);
for(Future f : result) {
String resultFromService = f.get(); // blocker, it will wait until the execution is over
}
//根据Maciej的评论将其同步:
failedServiceUrls=Collections.synchronizedList(failedServiceUrls);
ExecutorService ExecutorService=Executors.newFixedThreadPool(serviceUrls.getServiceUrls().size());
List runnables=new ArrayList().stream().map(o->new Callable()){
@凌驾
公共字符串调用()引发异常{
ResponseEntity response=rest.getForEntity(serviceUrl,String.class);
//对回应做点什么
如果(!response.getStatusCode().is2xxSuccessful()){
failedServiceUrls.add(serviceUrl);
}
返回response.getBody();
}
}).collect(toList());