【问题标题】:Efficient way to do async call in Spring REST在 Spring REST 中进行异步调用的有效方法
【发布时间】:2018-12-14 06:35:01
【问题描述】:

我有两个端点:/parent/child/{parentId} 两者都将返回列表

假设每次调用需要两秒钟。 因此,如果我打电话给/parent 并在列表中有 10 个父母,并且我想打电话给每个孩子并填充每个孩子,我总共需要 22 秒(/parent 需要 2 秒,/child/{parentId} 10 次,每次 2 秒)

在 Spring 和 Java 10 中,我可以使用 RestTemplate,结合 Future 进行异步调用。
在这个 sn-p 中,/slow-five 是对父级的调用,而/slow-six 是对子级的调用。

public List<Child> runSlow2() {
    ExecutorService executor = Executors.newFixedThreadPool(5);

    long start = System.currentTimeMillis();
    RestTemplate restTemplate = new RestTemplate();
    var futures = new ArrayList<Future<List<Child>>>();
    var result = new ArrayList<Child>();

    System.out.println("Start took (ms) : " + (System.currentTimeMillis() - start));
    var responseFive = restTemplate.exchange("http://localhost:8005/api/r/slow-five", HttpMethod.GET, null,
            new ParameterizedTypeReference<ResponseWrapper<Parent>>() {
            });

    for (var five : responseFive.getBody().getData()) {
        // prepare future
        var future = executor.submit(new Callable<List<Child>>() {

            @Override
            public List<Child> call() throws Exception {
                var endpointChild = "http://localhost:8005/api/r/slow-six/" + five.getId();

                var responseSix = restTemplate.exchange(endpointChild, HttpMethod.GET, null,
                        new ParameterizedTypeReference<ResponseWrapper<Child>>() {
                        });

                return responseSix.getBody().getData();
            }
        });

        futures.add(future);
    }

    for (var f : futures) {
        try {
            result.addAll(f.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    System.out.println("Before return took (ms) : " + (System.currentTimeMillis() - start));

    return result;
}

忽略 ResponseWrapper。它只是这样的包装类

public class ResponseWrapper<T> {
    private List<T> data;
    private String next;
}

代码运行良好,从 10 个父母那里收集所有孩子大约需要 3-4 秒。但我不认为它是有效的。
此外,Spring 5 有 WebClient 应该能够做这种事情。
但是,我找不到这种分层调用的任何示例。 WebClient 上的大多数示例仅涉及对单个端点的简单调用而没有依赖关系。
任何线索如何使用 WebClient 来实现相同的目标?异步调用多个/child并合并结果?

谢谢

【问题讨论】:

标签: java spring reactive-programming spring-webflux


【解决方案1】:

从 10 位家长那里收集所有孩子大约需要 3-4 秒。


我认为我们应该弄清楚是什么减慢了方法 runSlow2()。
您的方法对端点进行了多次调用。您可以通过执行调用并行性并从中收集结果来提高性能。
我不认为 restTemplate 很慢,你的代码没有问题,也许你的端点很慢。
一项改进可以不是对 /child/{parentId} 进行多个并行调用,而是可以引入一个接受 parentId 列表的新端点。 希望对您有所帮助。

【讨论】:

  • 你在说什么,所有端点调用都是并行运行的,方法是将它们放入期货中,然后通过get() 检索它们。
  • 实际端点/parent/child是外部端点。我无法控制或增强它们。 sn-p 只是举例
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-13
  • 2011-09-24
  • 2020-06-05
  • 1970-01-01
  • 2014-09-13
  • 2012-02-09
相关资源
最近更新 更多