外部サービス呼び出しを行うためにAsyncRestTemplate
を効果的に使用する方法がわかりません。以下のコードの場合:
_class Foo {
public void doStuff() {
Future<ResponseEntity<String>> future1 = asyncRestTemplate.getForEntity(
url1, String.class);
String response1 = future1.get();
Future<ResponseEntity<String>> future2 = asyncRestTemplate.getForEntity(
url2, String.class);
String response2 = future2.get();
Future<ResponseEntity<String>> future3 = asyncRestTemplate.getForEntity(
url3, String.class);
String response3 = future3.get();
}
}
_
理想的には、3つの呼び出しすべてを同時に実行し、すべて完了したら結果を処理したいです。 ただし、各外部サービス呼び出しはnotget()
が呼び出されるまでフェッチされるただし、get()
はブロックされます。だから、それはAsyncRestTemplate
の目的に反しませんか? RestTemplate
も使用できます。
だから私はそれらを同時に実行させる方法を理解していないのですか?
すべての非同期呼び出しをディスパッチする前に、ブロックget()
を呼び出さないでください。
_class Foo {
public void doStuff() {
ListenableFuture<ResponseEntity<String>> future1 = asyncRestTemplate
.getForEntity(url1, String.class);
ListenableFuture<ResponseEntity<String>> future2 = asyncRestTemplate
.getForEntity(url2, String.class);
ListenableFuture<ResponseEntity<String>> future3 = asyncRestTemplate
.getForEntity(url3, String.class);
String response1 = future1.get();
String response2 = future2.get();
String response3 = future3.get();
}
}
_
dispatchとgetの両方をループで実行できますが、現在の結果の収集は、次の未完成の未来で行き詰まるため、効率が悪いことに注意してください。
すべてのフューチャをコレクションに追加し、それを反復処理して、各フューチャの非ブロッキングisDone()
をテストできます。その呼び出しがtrueを返したら、get()
を呼び出すことができます。
これにより、get()
sを呼び出す順序で次の遅い将来の結果を待つのではなく、大量の結果収集が最適化されます。
さらに良いのは、ListenableFuture
によって返される各AccyncRestTemplate
内にコールバック(ランタイム)を登録でき、潜在的な結果を周期的に検査することを心配する必要がないことです。
「AsyncRestTemplate」を使用する必要がない場合は、代わりにRxJavaを使用することをお勧めします。 RxJava Zip 演算子が探しています。以下のコードを確認してください。
private rx.Observable<String> externalCall(String url, int delayMilliseconds) {
return rx.Observable.create(
subscriber -> {
try {
Thread.sleep(delayMilliseconds); //simulate long operation
subscriber.onNext("response(" + url + ") ");
subscriber.onCompleted();
} catch (InterruptedException e) {
subscriber.onError(e);
}
}
);
}
public void callServices() {
rx.Observable<String> call1 = externalCall("url1", 1000).subscribeOn(Schedulers.newThread());
rx.Observable<String> call2 = externalCall("url2", 4000).subscribeOn(Schedulers.newThread());
rx.Observable<String> call3 = externalCall("url3", 5000).subscribeOn(Schedulers.newThread());
rx.Observable.Zip(call1, call2, call3, (resp1, resp2, resp3) -> resp1 + resp2 + resp3)
.subscribeOn(Schedulers.newThread())
.subscribe(response -> System.out.println("done with: " + response));
}
外部サービスへのすべてのリクエストは個別のスレッドで実行され、最後の呼び出しが終了すると、変換関数(例:単純な文字列の連結)が適用され、結果(連結された文字列)がobservableから送信されます。
あなたの質問で理解しているのは、事前定義された非同期メソッドがあり、RestTemplateクラスを使用してこのメソッドを非同期に呼び出すことです。
メソッドを非同期に呼び出すのに役立つメソッドを作成しました。
public void testMyAsynchronousMethod(String... args) throws Exception {
// Start the clock
long start = System.currentTimeMillis();
// Kick of multiple, asynchronous lookups
Future<String> future1 = asyncRestTemplate
.getForEntity(url1, String.class);;
Future<String> future2 = asyncRestTemplate
.getForEntity(url2, String.class);
Future<String> future3 = asyncRestTemplate
.getForEntity(url3, String.class);
// Wait until they are all done
while (!(future1 .isDone() && future2.isDone() && future3.isDone())) {
Thread.sleep(10); //10-millisecond pause between each check
}
// Print results, including elapsed time
System.out.println("Elapsed time: " + (System.currentTimeMillis() - start));
System.out.println(future1.get());
System.out.println(future2.get());
System.out.println(future3.get());
}
CompletableFuture
クラス( javadoc )を使用することもできます。
呼び出しをCompletableFuture
に変換します。例えば。
_final CompletableFuture<ResponseEntity<String>> cf = CompletableFuture.supplyAsync(() -> {
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
});
_
次に、新しく作成した3つの完了可能な先物で_CompletableFuture::allOf
_メソッドを呼び出します。
結果に対してjoin()
メソッドを呼び出します。結果の完成可能な未来が解決された後、ステップ3で作成した各完成した未来から結果を取得できます。