如何使用 Netty 关闭异步 Http 请求的 AsyncHttpClient?
How to close AsyncHttpClient with Netty for an asynchronous Http request?
使用 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 is an abstraction layer that can work on top of the bare JDK, Netty and Grizzly. Note that the JDK implementation is very limited and you should REALLY use the other real providers.
要在 Netty 中使用 AsyncHttpClient,我们只需要在 java class 路径中包含相应的库。因此,我们可能 运行 之前的 Program
使用以下 class 路径配置之一来使用 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
为了正确使用Netty provider,我们还应该做些什么呢?例如,我正在关闭 AsyncCompletionHandler
中的 AsyncHttpClient
。对吗?
是否有任何配置可以改变观察到的行为?
使用 netty 提供程序并在调试器中逐步执行它,我看到在回调中调用 asyncHttpClient.close() 会导致 NioSocketChannelFactory.releaseExternalResources() 在尝试关闭时失败。抛出异常,这很可能导致非守护线程保留,并阻止 vm 退出。抛出的异常记录在 WARN 中,因此您可能看不到它(如果您将 slf4j-log4j12-1.7.7.jar 添加到类路径中,您应该会看到它)。所以你不能在回调中调用 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)
使用 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 is an abstraction layer that can work on top of the bare JDK, Netty and Grizzly. Note that the JDK implementation is very limited and you should REALLY use the other real providers.
要在 Netty 中使用 AsyncHttpClient,我们只需要在 java class 路径中包含相应的库。因此,我们可能 运行 之前的 Program
使用以下 class 路径配置之一来使用 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
为了正确使用Netty provider,我们还应该做些什么呢?例如,我正在关闭 AsyncCompletionHandler
中的 AsyncHttpClient
。对吗?
是否有任何配置可以改变观察到的行为?
使用 netty 提供程序并在调试器中逐步执行它,我看到在回调中调用 asyncHttpClient.close() 会导致 NioSocketChannelFactory.releaseExternalResources() 在尝试关闭时失败。抛出异常,这很可能导致非守护线程保留,并阻止 vm 退出。抛出的异常记录在 WARN 中,因此您可能看不到它(如果您将 slf4j-log4j12-1.7.7.jar 添加到类路径中,您应该会看到它)。所以你不能在回调中调用 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)