我正在使用的应用程序将按以下顺序使用2个REST Web服务:
1)计数记录 - 了解特定时间范围内的记录数量。
2)获取记录 - 一旦我们有多个记录,那么我们需要调用此服务。但是这个服务有一个阈值来一次获取10K记录。假设如果第一个服务在特定的时间间隔内告诉我,它有100K的记录,那么我需要以分页的方式调用第二个Web服务10次,考虑到它的阈值一次性为10K。
因此,如果我将进行10次同步调用,那么我的应用程序响应速度太慢。所以我需要一种机制来进行异步调用。
我在后端代码中使用spring框架并使用rest模板进行Web服务调用。我希望找到对上述POST Web服务进行异步调用的最佳方法
我做了一些研究,发现Asynchronous方法非常有用,如下所示: https://spring.io/guides/gs/async-method/
如果这是一个正确的方法,或者他们是一个更好的异步电话方式,请指导我吗?寻找你的建议,谢谢!
答案 0 :(得分:1)
@Journycorner链接的是一个好的开始,但它并没有真正展示整个画面,因为它只发出一个请求。与Future
合作绝对是正确的道路。 Spring 4提供的AsyncRestTemplate
返回 function Particles(num) {
this.particleArray = []
for (var i = 0; i < num; i++) {
var c = getRandomColor();
var o = Math.floor(Math.random() * (100 - 0 + 1)) / 100;
var s = Math.floor(Math.random() * (15 - 5 + 1)) + 5;
var particleCount = Math.floor(Math.random() * (1000 - 250 + 1)) + 250;
var particle = {
color: c,
opacity: o,
size: s,
number: particleCount,
message: 'THIS IS THE PARTICLE: '+particleCount
}
this.particleArray.push(particle);
}
这一事实正是您想要使用的。
在我的手机上,所以无法写出完整的代码,但这大致是您想要做的。
Future
*更新* 创建完整的代码示例。
答案 1 :(得分:0)
如果确实必须使用Spring Implementation进行异步,这似乎是一个明智的想法。
答案 2 :(得分:0)
我假设您在一次执行中需要所有100k记录,以便将所有数据打包成文件或一次执行一些业务逻辑。 如果不是这样,那么重新考虑将所有数据加载到单个执行中的需要是明智的,这会导致jvm的内存使用或者遇到Outofmemory错误。
假设前者,Async可以选择执行并行线程并捕获和整理每个线程的响应。但是,您需要使用&#34;线程池大小&#34;并行保持并行执行的线程数的上限。任务执行者。 限制线程大小的另一个原因是避免使用太多并行调用来加载您的伙伴休息Web服务。最终,合作伙伴Web服务正在从数据库加载数据,这将为某些并行查询执行限制提供最佳性能。希望这有帮助!
答案 3 :(得分:0)
这只是对@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(response&lt; futures.size())循环块与future.get()来阻止方法返回最终组合响应,直到处理完所有异步调用。
@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 {
}
}