如何关闭和重新配置使用NettyAsyncHttpProvider的AsyncHttpClient

时间:2013-11-13 22:14:42

标签: java netty asynchttpclient

我正在构建AsyncHttpClient这样:

public AsyncHttpClient getAsyncHttpClient() {
    AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()
                    .setProxyServer(makeProxyServer())
                    .setRequestTimeoutInMs((int) Duration.create(ASYNC_HTTP_REQUEST_TIMEOUT_MIN, TimeUnit.MINUTES).toMillis())
                    .build();

    return new AsyncHttpClient(new NettyAsyncHttpProvider(config), config);
}

这在启动时被调用一次,然后传递返回值并在各个地方使用。 makeProxyServer()是我自己的函数,可以使我的代理设置返回ProxyServer个对象。我需要做的是能够更改代理服务器设置,然后重新创建AsyncHttpClient对象。但是,我不知道如何干净地关闭它。一点点搜索让我相信close()不是优雅的。我担心每次代理设置更改时都会启动一个新的执行程序和一组线程。这不会经常发生,但我的应用程序运行时很长。

我知道我可以为每个请求使用RequestBuilder.setProxyServer(),但我希望将其设置在一个位置,以便我的asyncHttpClient实例的所有呼叫者都遵守系统范围的代理设置开发者必须记住这样做。

重新配置或拆除并重建基于Netty的{​​{1}}的正确方法是什么?

2 个答案:

答案 0 :(得分:6)

使用AsyncHttpClient.close()的问题在于它关闭了提供程序使用的线程池执行程序,然后没有重新构建它就无法重新使用客户端,因为documentation ,ts关闭后,执行器实例无法重用。所以,如果你采用这种方式,就没有办法重新构建客户端(除非你实现自己的ExecutorService,这将有另一个关闭逻辑,但它还有很长的路要走,恕我直言。)

但是,通过查看NettyAsyncHttpProvider的实现,我可以看到它存储了对给定AsyncHttpClientConfig实例的引用,并调用其getProxyServerSelector()来获取每个新实例的代理设置NettyAsyncHttpProvider.execute(Request...)调用(即AsyncHttpClient执行的每个请求)。

然后,如果我们可以让getProxyServerSelector()返回ProxyServerSelector的可配置实例,那就可以了。

不幸的是,AsyncHttpClientConfig被设计为只读容器,由AsyncHttpClientConfig.Builder实例化。 为了克服这个限制,我们必须使用“包装/委托”方法来破解它:

  • 创建一个派生自AsyncHttpClientConfig的新类。该类应该包装给定的单独AsyncHttpClientConfig实例,并实现AsyncHttpClientConfig getter到该实例的委派。

  • 为了能够在任何给定的时间点返回我们想要的代理选择器,我们在此包装类中使此设置可变,并为其公开setter。

示例:

public class MyAsyncHttpClientConfig extends AsyncHttpClientConfig
{
  private final AsyncHttpClientConfig config;
  private ProxyServerSelector proxyServerSelector;

  public MyAsyncHttpClientConfig(AsyncHttpClientConfig config)
  {
    this.config = config;
  }

  @Override
  public int getMaxTotalConnections() { return config.maxTotalConnections; }

  @Override
  public int getMaxConnectionPerHost() { return config.maxConnectionPerHost; }

  // delegate the others but getProxyServerSelector()

  ...

  @Override
  public ProxyServerSelector getProxyServerSelector()
  { 
    return proxyServerSelector == null 
      ? config.getProxyServerSelector()
      : proxyServerSelector; 
  }

  public void setProxyServerSelector(ProxyServerSelector proxyServerSelector) 
  { 
    this.proxyServerSelector = proxyServerSelector;
  }
}
  • 现在,在您的示例中,使用我们的新包装器包装您的AsyncHttpClient配置实例,并使用它来配置AsyncHttpClient

示例:

MyAsyncHttpClientConfig myConfig = new MyAsyncHttpClientConfig(config); 
return new AsyncHttpClient(new NettyAsyncHttpProvider(myConfig), myConfig);
  • 每当您调用myConfig.setProxyServerSelector(newSelector)时,客户端中NettyAsyncHttpProvider实例执行的新请求都将使用新的代理服务器设置。

一些提示/警告:

  • 这种方法依赖于NettyAsyncHttpProvider的内部实施;因此,在可维护性,未来的Netty库版本升级策略等方面做出自己的判断。在升级到新版本之前,您可以随时查看Netty源代码。目前,我个人认为不太可能改变这个实现无效。

  • 您可以使用ProxyServerSelector获取ProxyServer com.ning.http.util.ProxyUtils.createProxyServerSelector(proxyServer) - 这正是AsyncHttpClientConfig.Builder所做的。

  • 给定示例没有用于访问proxyServerSelector的同步逻辑;您可能希望根据应用程序逻辑需要添加一些。

  • 也许提交AsyncHttpClient的功能请求以便为AsyncHttpProvider设置“配置工厂”是个好主意,这样所有这些复杂情况都会消失: - )< / p>

答案 1 :(得分:1)

您应该为所有未完成的请求持有RequestHandle实例。当你想要关闭时,你可以遍历并在所有这些上调用isFinished(),直到它们全部完成。然后你就知道你可以安全地关闭它,并且没有任何待处理的请求被杀死。

一旦关闭,只需建立一个新的。不要试图重用现有的。如果您有对它的引用,请更改它们以引用将返回当前的Factory。