当前位置: 首页 > 知识库问答 >
问题:

对同一web服务进行多个异步调用的最佳方法

晋骏喆
2023-03-14

我正在使用的应用程序将按以下顺序使用2个REST web服务:

1) 计数记录-了解特定时间范围内的记录数。

2)获取记录——一旦我们有了记录的数量,我们就需要调用这项服务。但是这项服务有一个门槛来一次性获取10K记录。假设第一个服务在特定的时间间隔内告诉我,它有100K的记录,那么我需要以分页方式调用第二个网络服务10次,考虑到它的阈值是一次10K的。

因此,如果我将进行10次同步调用,我的应用程序将太慢而无法响应。所以我需要一种机制来进行异步调用。

我在后端代码中使用spring框架,在web服务调用中使用rest模板。我希望找到对上述PostWeb服务进行异步调用的最佳方法

我做了一些研究,发现异步方法如下:https://spring.io/guides/gs/async-method/

您能告诉我这是我所看到的一种正确的方法吗?或者这是一种更好的异步调用方法吗?期待您的建议,谢谢!

共有3个答案

赏梓
2023-03-14

如果它真的必须是异步的,那么使用Spring实现似乎是一个明智的想法。

罗智刚
2023-03-14

这只是对@shawn答案的改进。在前面提供的实现中,有时我会遇到以下问题:

while (responses < futures.size()) {        
   for (Future<ResponseEntity<List<Record>>> future : futures) {
       if (future.isDone()) {
            responses++;
            try {
                ResponseEntity<List<Record>> responseEntity = future.get();
                fullListOfRecords.addAll(responseEntity.getBody());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
        }
    }
}

在这里,如果处理了6个线程,有时同一个线程被允许在上面的块中多次输入,所以它最终会有重复的记录作为响应。所以为了避免这种情况,我添加了回调块来创建最终响应,确保没有重复的响应,尽管我们仍然需要while(响应)

@Component
public class SampleAsyncService {
private RestTemplate restTemplate;
private AsyncRestTemplate asyncRestTemplate;

@Value("${myapp.batchSize:1000}")
private int batchSize;

public SampleAsyncService(AsyncRestTemplate asyncRestTemplate, RestTemplate restTemplate) {
    this.asyncRestTemplate = asyncRestTemplate;
    this.restTemplate = restTemplate;
}

public List<Record> callForRecords() {
    ResponseEntity<Integer> response = restTemplate.getForEntity("http://localhost:8081/countService",
            Integer.class);
    int totalRecords = response.getBody().intValue();
    List<Future<ResponseEntity<List<Record>>>> futures = new ArrayList<Future<ResponseEntity<List<Record>>>>();
    for (int offset = 0; offset < totalRecords;) {
        ListenableFuture<ResponseEntity<List<Record>>> future = asyncRestTemplate.exchange(
                "http://localhost:8081/records?startRow={}&endRow={}", HttpMethod.GET, null,
                new ParameterizedTypeReference<List<Record>>() {
                }, offset, batchSize);
        future.addCallback(
                new ListenableFutureCallback<ResponseEntity<ChatTranscript>>() {  
                    @Override  
                    public void onSuccess(ResponseEntity<ChatTranscript> response) {  
                        fullListOfRecords.addAll(responseEntity.getBody());
                        log.debug("Success: " + Thread.currentThread());  
                    }  

                    @Override  
                    public void onFailure(Throwable t) {
                        log.debug("Error: " + Thread.currentThread());
                    }  
                }
            );
        futures.add(future);
        offset = offset + batchSize;
    }

    int responses = 0;
    List<Record> fullListOfRecords = new ArrayList<Record>();
    while (responses < futures.size()) {
        for (Future<ResponseEntity<List<Record>>> future : futures) {
            if (future.isDone()) {
                responses++;
                try {
                    future.get();
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    return fullListOfRecords;
}

public class Record {
}

}

石喜
2023-03-14

@Journycorner linked是一个很好的开始,但它并没有真正展示整个画面,因为它只发出一个请求。使用Future无疑是正确的。Spring4提供了一个AsyncRestTemplate,它返回一个Future,这正是您想要使用的。

在我的手机上,所以无法写出完整的代码,但这大致就是你想要做的。

@Component
public class SampleAsyncService {
    private RestTemplate restTemplate;
    private AsyncRestTemplate asyncRestTemplate;

    @Value("${myapp.batchSize:1000}")
    private int batchSize;

    public SampleAsyncService(AsyncRestTemplate asyncRestTemplate, RestTemplate restTemplate) {
        this.asyncRestTemplate = asyncRestTemplate;
        this.restTemplate = restTemplate;
    }

    public List<Record> callForRecords() {
        ResponseEntity<Integer> response = restTemplate.getForEntity("http://localhost:8081/countService",
                Integer.class);
        int totalRecords = response.getBody().intValue();
        List<Future<ResponseEntity<List<Record>>>> futures = new ArrayList<Future<ResponseEntity<List<Record>>>>();
        for (int offset = 0; offset < totalRecords;) {
            ListenableFuture<ResponseEntity<List<Record>>> future = asyncRestTemplate.exchange(
                    "http://localhost:8081/records?startRow={}&endRow={}", HttpMethod.GET, null,
                    new ParameterizedTypeReference<List<Record>>() {
                    }, offset, batchSize);
            futures.add(future);
            offset = offset + batchSize;
        }

        int responses = 0;
        List<Record> fullListOfRecords = new ArrayList<Record>();
        while (responses < futures.size()) {
            for (Future<ResponseEntity<List<Record>>> future : futures) {
                if (future.isDone()) {
                    responses++;
                    try {
                        ResponseEntity<List<Record>> responseEntity = future.get();
                        fullListOfRecords.addAll(responseEntity.getBody());
                    } catch (InterruptedException | ExecutionException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return fullListOfRecords;
    }

    public class Record {
    }
}

*更新*创建完整的代码示例。

 类似资料:
  • 我是web服务开发的初学者。我们正在使用Spring3用java构建RESTWeb应用程序。 我们正在使用的Web服务具有异步登录方法。我们为他们提供了一个回调监听器URL,他们的服务在其中发回响应。 因此,当我们发送登录请求时,我们会收到一个空白响应作为确认。和服务发送一个响应,其中包含侦听器URL上的实际数据。 请帮助,我应该如何设计/实现调用登录服务作为同步调用?谢谢 编辑:下面是回发消息的

  • 我在Scala上使用Play 2.5,我创建了一个类,可以多次调用外部web服务。 外部Web服务在某些条件下被调用并得到ok或nok的简单响应。如果可以,那么我应该更新内部对象状态,如果可以,我现在什么也不做。 这是我的类,它将String的列表作为参数,并返回要在控制器中处理的对象的Future列表。 是列表类型的列表,但我希望它只是一个简单的响应列表。 1)如何简化和纠正我的代码以获得响应列

  • 在我的项目中,有一个返回类型为未来列表的方法。另一个开发人员也这样迭代过for循环 现在,我必须在处理列表的对象后立即对它执行某些操作。我该怎么做?即使我把一个for循环像 如果第一个对象未被处理,isDone()条件将失败,它将被忽略,第二次迭代将开始,我如何处理它? 这也可以使用ExecutorService完成吗??我不熟悉ExecutorService。 编辑:所以我编辑了服务类的方法2(

  • 问题内容: 我有两个从jquery到Web服务的ajax调用。 第一次调用()在javascript ()中开始一个间隔,并返回存储在会话变量中的消息的字符串数组。 第二个调用()上传用户并将状态保存在要返回的会话中。因此,UploadUsers将消息添加到Session,而GetMessages检索消息并将其显示给客户端。 问题是即使我异步调用这两个方法,也要等到完成。它只是加载。 我什至在要添

  • 同步调用异步方法最安全的方法是什么?

  • 我喜欢新的System.net.Http.HttpClient类。它有一个很好的简单的API,它不会抛出正常的错误。但它只是异步的。 我需要代码(深入服务器内部) 编辑:我让PM女士最近向我确认,有一个命令“任何可能采取>X MS(我忘了X)的API必须是异步的”,许多PMs将此解释为“只有异步”(不清楚这是否是意图)。因此,文档DB api只是异步的。