Java 同时调用多个Spring微服务URL

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

我有一个Spring引导应用程序,它将使用
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
  • 当使用来自2的流量时,使用
    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
  • 当使用来自2的流量时,使用
    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());