根據Apache HttpClient 4.5.6講解。
HttpClient使用如下方式創建HttpClient時,在build()中會默認給HttpClient設置一個連接池PoolingHttpClientConnectionManager
return HttpClientBuilder.create().build();
默認創建的HttpClient是默認保持連接的keepalive。
我們使用HttpClient請求第三方服務器時,如果請求的是同一個服務器的地址是可以提高訪問效率的。這是由於HTTP協議的底層是TCP,TCP建立連接的時候需要三次握手。如果使用連接池並keeplive是true,那麼就是一個長鏈接,在第一次握手成功後,後面的請求就都不需要握手了,直接請求數據,這樣就加快了訪問速度。但是,如果多次請求的不是同一個服務器,還是需要爲每次請求握手建立連接。如果項目中有對某一個平臺比如微信開放平臺有頻繁的調用,可以使用一個HttpClient去專門請求,這樣只會進行一次握手。
我們一般使用HttpClient後都會關閉,比如:
CloseableHttpResponse response = this.execute(target, request, context);
....
finally {
response.close();
}
那有沒有想過這樣關閉會對我上面說的長鏈接有影響嗎?
這樣關閉是沒有影響的,它還是在連接池中。close()最後會調用下面這個方法。在finally中的close傳入的參數是false,也就是會釋放掉鏈接,但是它並不會調用成功。因爲在前面已經執行過一次releaseConnection方法了。在response放回處理返回的結果的時候會調用close方法。那裏的參數使用的是ConnectionHolder類的reusable成員變量。所以如果前面的程序執行成功最後的finally中的close方法到releaseConnection方法的CAS時會執行失敗。
private void releaseConnection(boolean reusable) {
if (this.released.compareAndSet(false, true)) {
HttpClientConnection var2 = this.managedConn;
synchronized(this.managedConn) {
if (reusable) {
this.manager.releaseConnection(this.managedConn, this.state, this.validDuration, this.tunit);
} else {
try {
this.managedConn.close();
this.log.debug("Connection discarded");
} catch (IOException var9) {
if (this.log.isDebugEnabled()) {
this.log.debug(var9.getMessage(), var9);
}
} finally {
this.manager.releaseConnection(this.managedConn, (Object)null, 0L, TimeUnit.MILLISECONDS);
}
}
}
}
}
可以看到是通過reusable去判斷的。這個在CloseableHttpResponse構造的時候就已經設定了。
if (reuseStrategy.keepAlive(response, context)) {
// Set the idle duration of this connection
final long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
if (this.log.isDebugEnabled()) {
final String s;
if (duration > 0) {
s = "for " + duration + " " + TimeUnit.MILLISECONDS;
} else {
s = "indefinitely";
}
this.log.debug("Connection can be kept alive " + s);
}
connHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
connHolder.markReusable();
}
public void markReusable() {
this.reusable = true;
}
看這個大概就可以看出,就是通過keepAlive去判斷的。
回到前面的releaseConnection(),它沒有去關閉socket,而是將連接放入了一個鏈表供後面使用。然後再執行的時候去這個鏈表中獲取連接。這個鏈表是RouteSpecificPool類available成員變量。獲取連接使用的是getFree方法。
以上。