简体   繁体   English

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

[英]Calling multiples webservices at same time using Java

I would like to call 3 webservices in a same method, and each result will be setted in a object in like this code bellow: 我想以相同的方法调用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;
}

In this case above, I'm calling 3 different webservices, they takes about 5 seconds each one, then is not good continue with this code. 在上面的这种情况下,我要调用3个不同的Web服务,每个Web服务大约需要5秒钟,因此不好继续这段代码。 I would like to know what is the best way to call the 3 webservices at same time and how could I do it using this code as example. 我想知道同时调用这3个Web服务的最佳方法是什么,以及如何使用此代码作为示例来做到这一点。 I've searched some articles or even answers here, but I didn't figure out how to do it. 我在这里搜索了一些文章甚至答案,但是我不知道该怎么做。 Thanks for the patience. 感谢您的耐心配合。

Concurrency in Java is handled through the Thread class. Java中的并发通过Thread类处理。 The Thread constructor accepts a Runnable parameter with the code for the Thread to run. Thread构造函数接受Runnable参数以及要运行的Thread的代码。 When the start() method is called, the JVM creates the new thread and executes the code in the run() method of the Runnable . 调用start()方法时,JVM将创建新线程并执行Runnablerun()方法中的代码。

Since Runnable only has the single abstract method run() , you can use a lambda expression for more readable code. 由于Runnable仅具有单个抽象方法run() ,因此您可以将lambda表达式用于更具可读性的代码。 I used traditional syntax for the first call and lambda syntax for the other 2 to demonstrate both methods. 我将传统语法用于第一个调用,将lambda语法用于其他两个调用,以演示这两种方法。

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;
}

The join() method blocks program execution until the calling Thread has finished running. join()方法将阻止程序执行,直到调用Thread完成运行为止。 By placing the join() s at the end of the method, you can guarantee that all 3 requests have finished before you return. 通过将join()放置在方法的末尾,可以保证在返回之前,所有3个请求均已完成。 If it doesn't matter whether those requests have finished before you return, you can simply remove the join() s and the requests will continue in the background while the rest of your application runs. 如果这些请求在返回之前是否已完成无关紧要,则只需删除join() ,这些请求将在后台运行,而其余的应用程序将运行。

For larger applications, Java also includes thread pools which will manage the creation of Thread s for you. 对于较大的应用程序,Java还包括线程池 ,该线程池将为您管理Thread的创建。 Since your application only uses the same 3 Runnable s in a local context, I think the solution above is better suited (and more educational for the purposes of this answer). 由于您的应用程序仅在本地上下文中使用相同的3 Runnable ,因此我认为上述解决方案更合适(并且对于此答案更具有教育意义)。

You can use ExecutorService to submit Callable and call Future.get() to retrieve result as shown below (change Future<String> to the appropriate return value). 您可以使用ExecutorService提交Callable并调用Future.get()来检索结果,如下所示(将Future <String>更改为适当的返回值)。 You should also think about error handling and creating threadpool outside of method (if possible at app startup). 您还应该考虑在方法之外进行错误处理和创建线程池(如果可能在应用程序启动时)。

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;
  }

I started writing this answer in the night and then left it for the next day. 我从晚上开始写这个答案,然后将其留给第二天。 By the morning two answers were given and one of those was accepted by OP. 到了早上,给出了两个答案,其中一个被OP接受。 Leaving this answer here for anyone who wishes to see the complete design and idea of the implementation, instead of actual code. 对于希望查看实现的完整设计和构思而不是实际代码的任何人,这里都保留了此答案。


The Design: 该设计:

Since web service calls take time to respond, they are called asynchronously, meaning that the main thread is not synchronized with these calls. 由于Web服务调用花费时间来响应,因此它们被异步调用,这意味着主线程不与这些调用同步。

So, they are designed such that you make individual calls on separate threads. 因此,它们的设计使您可以在单独的线程上进行单独的调用。

For your case, the important Java elements are: 对于您的情况,重要的Java元素是:

  1. Callable Interface ; 可调用接口 ;
  2. Future Interface ; 未来接口 ;
  3. ExecutorService . ExecutorService

The Implementation: 实施:

  1. Implement a class which extends implements the Callable interface and contains the calling code for the web service in the call() method. 实现一个扩展该类的类,该类实现Callable接口,并在call()方法中包含Web服务的调用代码。
    • Do that for all three web service calls; 对所有三个Web服务调用都执行此操作;
  2. Start an ExecutorService which will do this calling and result gathering for you; 启动一个ExecutorService,它将执行此调用并为您收集结果;
  3. When you have to make the call, create an instance of the three calls and store them in an ArrayList; 当您必须进行调用时,请创建这三个调用的实例并将其存储在ArrayList中;
  4. Using the ExecutorService you created in step 2, invoke the instances you created in step 3. 使用在步骤2中创建的ExecutorService,调用在步骤3中创建的实例。

Bonus Step: It seems to me that the three web service calls need to be made in the same order repeatedly (I don't understand the language - it isn't English). 奖励步骤:在我看来,这三个Web服务调用需要以相同的顺序重复进行(我听不懂语言-它不是英语)。 For such a code, a separate orchestrator class can be created at the top of classes created in step 1 of the implementation. 对于这样的代码,可以在实现的步骤1中创建的类的顶部创建一个单独的协调器类。

This orchestrator class can extend Thread class and make the three web service calls. 该协调器类可以扩展Thread类并进行三个Web服务调用。 Now, this one class can be run asynchronously, instead of making the three web service calls. 现在,该类可以异步运行,而不用进行三个Web服务调用。 Keeps the code modular and abstracts away the complexity. 使代码保持模块化并消除复杂性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM