2017-02-17 31 views
0

Итак, у меня есть веб-приложение в Spring Boot, и есть часть, где я делаю много HTTP-запросов API, и кажется, что тайм-аут возникает, если сделано слишком много запросов. Я слышал, что переход с синхронного на асинхронный запрос может помочь в этой проблеме.Java - получение результата из OkHttp Asynchronous GET

Использование OkHttp, это то, что мой Синхронный запрос GET выглядит следующим образом:

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()); 

    } 
} 

я вернуть ответ как объект JSON от разбора тела ответа. Однако, пытаясь использовать асинхронный вызов OkHttp, кажется, что я не могу использовать тот же подход. Это то, что я до сих пор:

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()); 
     } 
    }); 
} 

Я не могу просто вернуть результат как JSON, так как ответ обернут внутри метода обратного вызова, который имеет возвращаемое значение ничтожных. Любые идеи о том, как я могу добиться аналогичных результатов для моего синхронного GET для извлечения ответа?

+0

Это не дает никаких преимуществ при изменении асинхронного вызова. В идеале вы должны вернуть что-то вроде Будущего в веб-фреймворк, который вызывает вас, и он будет обрабатывать завершение будущего асинхронно. Если вам нужно вернуть завершенный результат вашему абоненту за один запрос, который вы делаете, то независимо от того, каким он будет синхронным звонком. Другая возможность заключается в том, что ваш конечный результат зависит от многих запросов, и в этом случае помощь будет выполняться синхронно и одновременно. –

+0

Хмм интересно. В моем случае, есть много HTTP-запросов, созданных с целью анализа и агрегирования всех результатов и хранения содержимого в строке. Похоже, что синхронные параллельные запросы могут быть тем, что мне нужно делать. Будет ли этот асинхронный метод не подходящим для моей проблемы? –

+0

На самом деле это звучит идеально. Вы можете иметь асинхронные задачи, получая данные одновременно, а также одновременно анализировать, а затем блокировать синхронно, пока все отдельные результаты не будут завершены. –

ответ

2

Я не пользователь Spring Boot, так что это не полный ответ. Но если он поддерживает возвращение Будущего, то тривиально переходить от обратного вызова OkHttp к Будущему.

Это может иметь отношение https://spring.io/guides/gs/async-method/

Что касается производства будущего

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); 
    } 
} 

А потом Епдиеей работы что-то вроде

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(); 
    } 
    }); 

Если у вас есть несколько запросов для обработки вы можете отправить их отдельно, а затем ждать, пока все результаты будут доступны до объединения и возврата

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)); 
    }