如何使用 Netty 关闭异步 Http 请求的 AsyncHttpClient?

How to close AsyncHttpClient with Netty for an asynchronous Http request?

使用 AsyncHttpClientNetty 提供程序将防止主程序在我们执行异步请求时终止。 例如,以下程序是否在 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,或者不使用:

为了正确使用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)