7

我正在构建一个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基于- 的正确方法是AsyncHttpClient什么?

4

2 回答 2

7

using 的问题AsyncHttpClient.close()是它关闭了提供者使用的线程池执行器,然后没有办法在不重新构建它的情况下重用客户端,因为根据文档,一旦 ts 关闭,执行器实例就不能被重用. 所以,如果你这样做,除了重新构建客户端之外别无他法(除非你实现自己的 ExecutorService ,它会有另一个关闭逻辑,但这是一个很长的路要走,恕我直言)。

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

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

不幸的是,AsyncHttpClientConfig它被设计为只读容器,由AsyncHttpClientConfig.Builder. 为了克服这个限制,我们必须破解它,比如使用“wrap/delegate”方法:

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

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

例子:

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获得- 这正是它所做的。ProxyServercom.ning.http.util.ProxyUtils.createProxyServerSelector(proxyServer)AsyncHttpClientConfig.Builder

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

  • 也许提交功能请求以便AsyncHttpClient能够设置“配置工厂”是一个好主意,AsyncHttpProvider这样所有这些复杂性都会消失:-)

于 2014-02-26T15:34:44.310 回答
1

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

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

于 2014-02-26T08:08:29.810 回答