在Spring REST中进行异步调用的有效方法

时间:2018-12-14 06:35:02

标签: java spring reactive-programming spring-webflux

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

让我们假设每次通话将花费两秒钟。 因此,如果我打电话给/parent并在列表中有10个父母,并且我想打电话给每个孩子并填充每个孩子,那么我总共需要22秒(/parent只需2秒,是/child/{parentId}的10倍每次2秒)

在Spring和Java 10中,我可以结合使用RestTemplateFuture进行异步调用。
在此代码段中,/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;
}

该代码运行正常,花了大约3-4秒的时间才能收集10个父母的所有孩子。但是我觉得效率不高。
此外,Spring 5具有WebClient应该可以执行此类操作的功能。
但是,我找不到这种分层调用的任何示例。 WebClient上的大多数示例仅涉及对单个端点的简单调用,而没有依赖性。
有什么线索可以使用WebClient实现相同的目的吗?异步调用多个/child并合并结果?

谢谢

1 个答案:

答案 0 :(得分:0)

  

从10个父母那里收集所有孩子大约需要3-4秒。


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