簡體   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