2017-02-17 8 views
0

Ich habe also eine Web-App in Spring Boot, und es gibt einen Teil, wo ich viele HTTP-Anfragen an eine API, und es scheint Timeout, wenn zu viele Anfragen gemacht werden. Ich habe gehört, dass der Wechsel von synchronen zu asynchronen Anfragen dieses Problem beheben könnte.Java - Ergebnis von OkHttp Asynchronous GET

Mit OkHttp, das ist, was meine Synchron-GET-Anfrage wie folgt aussieht:

private JSONObject run(String url) throws Exception { 
    Request newRequest = new Request.Builder() 
      .url(url) 
      .addHeader("Authorization", token) 
      .build(); 

    try (Response response = client.newCall(newRequest).execute()) { 
     if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); 
     return new JSONObject(response.body().string()); 

    } 
} 

kehre ich die Antwort als JSON-Objekt aus Parsen der Antworttext. Bei dem Versuch, einen asynchronen OkHttp-Aufruf zu verwenden, scheint es mir jedoch nicht möglich zu sein, denselben Ansatz zu verwenden. Das ist, was ich habe, so weit:

public void runAsync(String url) throws Exception { 
    Request request = new Request.Builder() 
      .url(url) 
      .addHeader("Authorization", token) 
      .build(); 

    client.newCall(request).enqueue(new Callback() { 
     @Override public void onFailure(Call call, IOException e) { 
      e.printStackTrace(); 
     } 

     @Override public void onResponse(Call call, Response response) throws IOException { 
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); 

      System.out.println(response.body().string()); 
     } 
    }); 
} 

Ich kann nicht einfach das Ergebnis als JSON zurückgeben, da die Reaktion innerhalb der Callback-Methode gewickelt wird, die einen Rückgabewert von Leere hat. Irgendwelche Ideen, wie ich ähnliche Ergebnisse zu meinem synchronen GET erzielen könnte, um die Antwort zu extrahieren?

+0

Dies führt nicht wirklich zu den Vorteilen eines asynchronen Anrufs. Im Idealfall würden Sie so etwas wie ein Future an das Web-Framework zurückgeben, das Sie aufruft, und es würde die Fertigstellung der Zukunft asynchron erledigen. Wenn Sie Ihrem Anrufer ein abgeschlossenes Ergebnis für eine einzelne Anfrage zurückgeben müssen, die Sie tätigen, dann ist es unabhängig davon, was ein synchroner Anruf ist. Die andere Möglichkeit ist, dass Ihr Endergebnis von vielen Anfragen abhängt. In diesem Fall würde es hilfreich sein, diese synchron und gleichzeitig ausführen zu lassen. –

+0

Hmm interessant. In meinem Fall gibt es viele HTTP-Anfragen mit dem Ziel, alle Ergebnisse zu analysieren und zu aggregieren und den Inhalt in einer Zeichenkette zu speichern. Es klingt wie synchrone gleichzeitige Anfragen, was ich tun muss. Würde diese asynchrone Methode nicht zu meinem Problem passen? –

+0

Eigentlich klingt das immer noch ideal. Sie können die asynchronen Tasks veranlassen, Daten gleichzeitig zu holen und gleichzeitig zu analysieren und dann synchron zu blockieren, bis alle individuellen Ergebnisse vollständig sind. –

Antwort

2

Ich bin kein Benutzer von Spring Boot, also ist dies keine vollständige Antwort. Aber wenn es die Rückkehr einer Zukunft unterstützt, dann ist es einfach, von OkHttp Callback zu einer Zukunft zu überbrücken.

Dies kann https://spring.io/guides/gs/async-method/

Als zur Herstellung der Zukunft

public class OkHttpResponseFuture implements Callback { 
    public final CompletableFuture<Response> future = new CompletableFuture<>(); 

    public OkHttpResponseFuture() { 
    } 

    @Override public void onFailure(Call call, IOException e) { 
    future.completeExceptionally(e); 
    } 

    @Override public void onResponse(Call call, Response response) throws IOException { 
    future.complete(response); 
    } 
} 

Und dann enqueue der Job so etwas wie

OkHttpResponseFuture callback = new OkHttpResponseFuture(); 
    client.newCall(request).enqueue(callback); 

    return callback.future.thenApply(response -> { 
    try { 
     return convertResponse(response); 
    } catch (IOException e) { 
     throw Throwables.propagate(e); 
    } finally { 
     response.close(); 
    } 
    }); 

Wenn Sie mehrere Anforderungen relevant sein, das Sie sie verarbeiten einreichen getrennt und warten Sie dann auf alle Ergebnisse zur Verfügung stehen vor dem Kombinieren und Zurückgeben

public static <T> CompletableFuture<List<T>> join(List<CompletableFuture<T>> futures) { 
    CompletableFuture[] cfs = futures.toArray(new CompletableFuture[futures.size()]); 

    return CompletableFuture.allOf(cfs) 
     .thenApply(v -> combineIndividualResults(c)); 
    }