Как закрыть AsyncHttpClient с Netty для асинхронного Http-запроса?
С помощью AsyncHttpClient
С Netty
поставщик предотвратит завершение основной программы при выполнении асинхронного запроса.
Например, следующая программа завершается после println
, или нет, в зависимости от поставщика JDKAsyncHttpProvider
или NettyAsyncHttpProvider
:
public class Program {
public static CompletableFuture<Response> getDataAsync(String uri) {
final AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
final CompletableFuture<Response> promise = new CompletableFuture<>();
asyncHttpClient
.prepareGet(uri)
.execute(new AsyncCompletionHandler<Response>(){
@Override
public Response onCompleted(Response resp) throws Exception {
promise.complete(resp);
asyncHttpClient.close(); // ??? Is this correct ????
return resp;
}
});
return promise;
}
public static void main(String [] args) throws Exception {
final String uri = "…";
System.out.println(getDataAsync(uri).get());
}
}
о AsynHttpClient
в документации:
AHC-это слой абстракции, который может работать поверх голого JDK, Netty и Grizzly. Обратите внимание, что реализация JDK очень ограничен,и вы действительно должны использовать других реальных поставщиков.
чтобы использовать AsyncHttpClient с Netty, нам просто нужно включить соответствующую библиотеку в путь к классу java. Итак, мы можем запустить предыдущий Program
С одной из следующих конфигураций пути класса для использования Netty или нет:
-
-cp .;async-http-client-1.9.24.jar;netty-3.10.3.Final.jar;slf4j-api-1.7.12.jar
использоватьNettyAsyncHttpProvider
-
-cp .;async-http-client-1.9.24.jar;slf4j-api-1.7.12.jar
использоватьJDKAsyncHttpProvider
что еще мы должны сделать, чтобы использовать поставщика Нетти правильно? Например, я закрываю AsyncHttpClient
на AsyncCompletionHandler
. Это верно?
есть ли настройки для изменения наблюдаемого поведения?
1 ответов
используя поставщик netty и проходя через него в отладчике, я вижу, что вызов asyncHttpClient.close () внутри обратного вызова вызывает NioSocketChannelFactory.releaseExternalResources () для сбоя при попытке выполнить его завершение работы. Создается исключение, и это, скорее всего, приведет к тому, что поток не демона останется и не позволит виртуальной машине выйти. Исключение регистрируется при предупреждении, поэтому вы, вероятно, не видите его (если вы добавляете slf4j-log4j12-1.7.7.jar для вас classpath вы должны увидеть он.) Таким образом, вы не можете вызвать close() в обратном вызове (и вам не нужно закрывать его после каждого выполнения запроса).
вот трассировка:
WARN [New I/O worker #1] (NettyAsyncHttpProvider.java:79) - Unexpected error on close
java.lang.IllegalStateException: Must not be called from a I/O-Thread to prevent deadlocks!
at org.jboss.netty.channel.socket.nio.AbstractNioSelector.shutdown(AbstractNioSelector.java:415)
at org.jboss.netty.channel.socket.nio.NioWorker.shutdown(NioWorker.java:36)
at org.jboss.netty.channel.socket.nio.AbstractNioWorkerPool.shutdown(AbstractNioWorkerPool.java:142)
at org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory.releaseExternalResources(NioClientSocketChannelFactory.java:225)
at com.ning.http.client.providers.netty.channel.ChannelManager.close(ChannelManager.java:355)
at com.ning.http.client.providers.netty.NettyAsyncHttpProvider.close(NettyAsyncHttpProvider.java:70)
at com.ning.http.client.AsyncHttpClient.close(AsyncHttpClient.java:336)
at com.cie.program.Program.onCompleted(Program.java:23)