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

Java 如何使用Netty关闭异步Http请求的AsyncHttpClient?,java,asynchronous,netty,asynchttpclient,completable-future,Java,Asynchronous,Netty,Asynchttpclient,Completable Future,在执行异步请求时,将AsyncHttpClient与Netty提供程序一起使用将防止主程序终止。 例如,以下程序在println之后终止,这取决于提供程序是JDKAsyncHttpProvider还是nettysynchttpprovider: public class Program { public static CompletableFuture<Response> getDataAsync(String uri) { final AsyncHttpCl

在执行异步请求时,将
AsyncHttpClient
Netty
提供程序一起使用将防止主程序终止。 例如,以下程序在
println
之后终止,这取决于提供程序是
JDKAsyncHttpProvider
还是
nettysynchttpprovider

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());
    }
}
公共类程序{
公共静态CompletableFuture getDataAsync(字符串uri){
final AsyncHttpClient AsyncHttpClient=new AsyncHttpClient();
最终CompletableFuture承诺=新的CompletableFuture();
异步HttpClient
.prepareGet(uri)
.execute(新的AsyncCompletionHandler(){
@凌驾
公共响应onCompleted(响应响应)引发异常{
承诺。完成(resp);
asyncHttpClient.close();/?是否正确????
返回响应;
}
});
回报承诺;
}
公共静态void main(字符串[]args)引发异常{
最后一个字符串uri=“…”;
System.out.println(getDataAsync(uri.get());
}
}
关于
AsynHttpClient
文档说明:

AHC是一个抽象层,可以在裸JDK、Netty和Grizzly之上工作。请注意,JDK实现非常有限,您应该真正使用其他真正的提供者

要将AsyncHttpClient与Netty一起使用,我们只需要在java类路径中包含相应的库。因此,我们可以使用以下类路径配置之一运行前面的
程序
,以使用Netty,也可以不使用Netty:

  • -cp。;async-http-client-1.9.24.jar;netty-3.10.3.Final.jar;slf4j-api-1.7.12.jar
    将使用
    nettysynchuttprovider
  • -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$1.onCompleted(Program.java:23)

AsyncHttpClient
不是线程安全的吗?不要在每次方法调用时都创建一个新的客户端。如果您尝试在很久之后关闭客户端,例如在
之后,然后接受
,您的应用程序是否会终止?否。关闭与否,asyncHttpClient对结果行为没有影响。当我尝试您的代码时,我收到此错误,可能正如它所说的,这是一个死锁问题。但你说过你没关上就试过了?警告[New I/O worker#1](NettyAsyncHttpProvider.java:79)-关闭java.lang.IllegalStateException时出现意外错误:不得从I/O线程调用以防止死锁!在org.jboss.netty.channel.socket.nio.AbstractNioSelector.shutdown(AbstractNioSelector.java:415)中,我得到了相同的行为,但是如果我将close()移到System.out.println之后,当我包含netty jar时,它确实会退出。但是你试着把它移近,但它还是不退出?