使用Java同时调用多个Web服务

时间:2018-07-22 02:07:38

标签: java multithreading performance parallel-processing

我想用相同的方法调用3个Web服务,并且每个结果都将在如下所示的对象中设置:

public Dossie procuraPorCPF(String cpf) {

    Dossie dossie = new Dossie();

    // first webservice call
    dossie.setCnh(detectaClientCnh.verificaCNH(cpf));

    // second webservice call
    dossie.setFotoCnh(detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf));

    // third webservice call
    dossie.setPm(consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult());

    return dossie;
}

在上面的这种情况下,我要调用3个不同的Web服务,每个服务大约需要5秒钟,因此不好继续这段代码。我想知道同时调用这3个Web服务的最佳方法是什么,以及如何使用此代码作为示例来做到这一点。我在这里搜索了一些文章甚至答案,但是我不知道该怎么做。感谢您的耐心等候。

3 个答案:

答案 0 :(得分:2)

Java中的并发通过Thread类进行处理。 Thread构造函数接受带有Runnable运行代码的Thread参数。调用start()方法时,JVM将创建新线程并执行run()的{​​{1}}方法中的代码。

由于Runnable仅具有单个抽象方法Runnable,因此您可以使用lambda expression获得更具可读性的代码。我对第一个调用使用传统语法,对其他两个调用使用lambda语法来演示这两种方法。

run()

public Dossie procuraPorCPF(String cpf) { Dossie dossie = new Dossie(); Thread[] threads = new Thread[3]; threads[0] = new Thread(new Runnable() { @Override public void run() { dossie.setCnh(detectaClientCnh.verificaCNH(cpf)); } }; threads[0].start(); threads[1] = new Thread(() -> dossie.setFotoCnh(detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf)); threads[1].start(); threads[2] = new Thread(() -> dossie.setPm(consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult()); threads[2].start(); try { threads[0].join(); threads[1].join(); threads[2].join(); } catch (InterruptedException e) { e.printStackTrace(); } return dossie; } 方法将阻止程序执行,直到调用join()完成运行为止。通过将Thread放在方法的末尾,可以保证在返回之前,所有3个请求均已完成。如果这些请求在返回之前是否已完成都没关系,则只需删除join(),这些请求将在后台运行,而其余的应用程序将运行。

对于大型应用程序,Java还包括thread pools,它将为您管理join()的创建。由于您的应用程序仅在本地上下文中使用相同的3 Thread,因此我认为上述解决方案更适合(并且对于此答案更具有教育意义)。

答案 1 :(得分:1)

您可以使用ExecutorService提交Callable并调用Future.get()来检索结果,如下所示(将Future 更改为适当的返回值)。您还应该考虑在方法之外进行错误处理和创建线程池(如果可能在应用启动时)。

public Dossie procuraPorCPF(String cpf) {

    ExecutorService executor = Executors.newFixedThreadPool(3);

    Future<String> cnh = executor.submit(() -> detectaClientCnh.verificaCNH(cpf));
    Future<String> fotoCnh = executor.submit(() -> detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf));
    Future<String> pm =
        executor.submit(() -> consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult());

    Dossie dossie = new Dossie();

    try {
      dossie.setCnh(cnh.get());
      dossie.setFotoCnh(fotoCnh.get());
      dossie.setPm(pm.get());
    } catch (InterruptedException | ExecutionException cause) {
      cause.printStackTrace();
    }
    executor.shutdown();
    return dossie;
  }

答案 2 :(得分:1)

我从晚上开始写这个答案,然后将其留给第二天。到了早上,给出了两个答案,其中一个被OP接受。对于希望查看实施的完整设计和思想而非实际代码的人,请在此处留下答案。


设计:

由于Web服务调用需要时间来响应,因此它们被异步调用,这意味着主线程与这些调用不同步。

因此,它们的设计使您可以在单独的线程上进行单独的调用。

对于您而言,重要的Java元素是:

  1. Callable Interface;
  2. Future Interface;
  3. ExecutorService

实施:

  1. 实现一个扩展类,该类实现Callable接口,并在call()方法中包含Web服务的调用代码。
    • 对所有三个Web服务调用执行该操作;
  2. 启动一个ExecutorService,它将执行此调用并为您收集结果;
  3. 当您必须进行调用时,创建三个调用的实例并将它们存储在ArrayList中;
  4. 使用您在步骤2中创建的ExecutorService,调用在步骤3中创建的实例。

奖励步骤:在我看来,这三个Web服务调用需要以相同的顺序重复进行(我听不懂语言,因为它不是英语)。对于这样的代码,可以在实现的第1步中创建的类的顶部创建一个单独的Orchestrator类。

此协调器类可以扩展Thread类并进行三个Web服务调用。现在,该类可以异步运行,而不用进行三个Web服务调用。使代码保持模块化并抽象出复杂性。