繁体   English   中英

重用 javax.ws.rs.client.Client

[英]Reusing javax.ws.rs.client.Client

我刚刚在我的代码上运行了一个分析器,我注意到我花了很多时间使用ClientBuilder.newClient()创建新客户端。 这并不奇怪,因为文档指出这是一项繁重的操作,如果可能,您应该重用客户端。

所以我创建了一个简单的资源池来管理我所有的客户

public class SimpleClientResourcePool implements ResourcePool<Client> {
    private LinkedList<Client> pool = new LinkedList<>();

    @Override
    public Optional get() {
        if(pool.isEmpty())
            return Optional.empty();
        return Optional.of(pool.getFirst());
    }

    @Override
    public void release(Client value) {
        pool.addLast(value);
    }
}

我像这样使用它

    Client client = clientResourcePool.get().orElseGet(ClientBuilder::newClient);
    Response response = get(countryId, uri, client);

    try {
      ///random code
    } finally {
        response.close();
        clientResourcePool.release(client);
    }

当我作为用户在本地运行时,我没有看到任何问题,但在加载期间似乎存在一个我不太了解的并发问题。

我收到一个似乎基于此错误的异常:

Caused by: java.lang.IllegalStateException: Connection is still allocated
        at org.apache.http.util.Asserts.check(Asserts.java:34)
        at org.apache.http.impl.conn.BasicHttpClientConnectionManager.getConnection(BasicHttpClientConnectionManager.java:266)
        at org.apache.http.impl.conn.BasicHttpClientConnectionManager$1.get(BasicHttpClientConnectionManager.java:217)
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190)
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
        at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
        at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:313)

那么这不是您应该重用客户端的方式,还是我遗漏了一些明显的东西?

关闭客户端似乎只会导致其他异常......

是的,您遇到的问题肯定与您的池实施有关。 我实际上在您的代码中看到至少 3 个问题:

  1. SimpleClientResourcePool不是线程安全的。 pool集合的访问不同步。 在您的情况下, Queue也将比LinkedList更好,因此请查看并发包提供的ConcurrentLinkedQueue
  2. 你应该退出Client从池中对象或将其移动到根据您的需要“使用客户”的另一个集合之前release不会调用它。
  3. 即使在一行 if 语句附近也始终执行 {} 如果您团队中的某个人在该“if”中添加了另一行,则自动合并后代码将不会编译。

应用此类建议,您可以从以下内容开始:

public class SimpleClientResourcePool implements ResourcePool<Client> {
    private final Queue<Client> pool = new ConcurrentLinkedQueue<>();

    @Override
    public Optional get() {
        return Optional.ofNullable(pool.poll());
    }

    @Override
    public void release(Client value) {
        pool.offer(value);
    }
}

希望能帮助到你!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM