httpclient connect連接請求方法源碼解讀
序
本文主要研究一下httpclient的connect
HttpClientConnectionOperator
org/apache/http/conn/HttpClientConnectionOperator.java
public interface HttpClientConnectionOperator { void connect( ManagedHttpClientConnection conn, HttpHost host, InetSocketAddress localAddress, int connectTimeout, SocketConfig socketConfig, HttpContext context) throws IOException; void upgrade( ManagedHttpClientConnection conn, HttpHost host, HttpContext context) throws IOException; }
HttpClientConnectionOperator定義了connect及upgrade方法,它有一個默認的實現(xiàn)類為DefaultHttpClientConnectionOperator
DefaultHttpClientConnectionOperator
org/apache/http/impl/conn/DefaultHttpClientConnectionOperator.java
public class DefaultHttpClientConnectionOperator implements HttpClientConnectionOperator { static final String SOCKET_FACTORY_REGISTRY = "http.socket-factory-registry"; private final Log log = LogFactory.getLog(getClass()); private final Lookup<ConnectionSocketFactory> socketFactoryRegistry; private final SchemePortResolver schemePortResolver; private final DnsResolver dnsResolver; public DefaultHttpClientConnectionOperator( final Lookup<ConnectionSocketFactory> socketFactoryRegistry, final SchemePortResolver schemePortResolver, final DnsResolver dnsResolver) { super(); Args.notNull(socketFactoryRegistry, "Socket factory registry"); this.socketFactoryRegistry = socketFactoryRegistry; this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE; this.dnsResolver = dnsResolver != null ? dnsResolver : SystemDefaultDnsResolver.INSTANCE; } //...... public void connect( final ManagedHttpClientConnection conn, final HttpHost host, final InetSocketAddress localAddress, final int connectTimeout, final SocketConfig socketConfig, final HttpContext context) throws IOException { final Lookup<ConnectionSocketFactory> registry = getSocketFactoryRegistry(context); final ConnectionSocketFactory sf = registry.lookup(host.getSchemeName()); if (sf == null) { throw new UnsupportedSchemeException(host.getSchemeName() + " protocol is not supported"); } final InetAddress[] addresses = host.getAddress() != null ? new InetAddress[] { host.getAddress() } : this.dnsResolver.resolve(host.getHostName()); final int port = this.schemePortResolver.resolve(host); for (int i = 0; i < addresses.length; i++) { final InetAddress address = addresses[i]; final boolean last = i == addresses.length - 1; Socket sock = sf.createSocket(context); sock.setSoTimeout(socketConfig.getSoTimeout()); sock.setReuseAddress(socketConfig.isSoReuseAddress()); sock.setTcpNoDelay(socketConfig.isTcpNoDelay()); sock.setKeepAlive(socketConfig.isSoKeepAlive()); if (socketConfig.getRcvBufSize() > 0) { sock.setReceiveBufferSize(socketConfig.getRcvBufSize()); } if (socketConfig.getSndBufSize() > 0) { sock.setSendBufferSize(socketConfig.getSndBufSize()); } final int linger = socketConfig.getSoLinger(); if (linger >= 0) { sock.setSoLinger(true, linger); } conn.bind(sock); final InetSocketAddress remoteAddress = new InetSocketAddress(address, port); if (this.log.isDebugEnabled()) { this.log.debug("Connecting to " + remoteAddress); } try { sock = sf.connectSocket( connectTimeout, sock, host, remoteAddress, localAddress, context); conn.bind(sock); if (this.log.isDebugEnabled()) { this.log.debug("Connection established " + conn); } return; } catch (final SocketTimeoutException ex) { if (last) { throw new ConnectTimeoutException(ex, host, addresses); } } catch (final ConnectException ex) { if (last) { final String msg = ex.getMessage(); throw "Connection timed out".equals(msg) ? new ConnectTimeoutException(ex, host, addresses) : new HttpHostConnectException(ex, host, addresses); } } catch (final NoRouteToHostException ex) { if (last) { throw ex; } } if (this.log.isDebugEnabled()) { this.log.debug("Connect to " + remoteAddress + " timed out. " + "Connection will be retried using another IP address"); } } } }
DefaultHttpClientConnectionOperator的connect先通過getSocketFactoryRegistry獲取Lookup<ConnectionSocketFactory>
,再通過它獲取ConnectionSocketFactory,之后通過dnsResolver解析地址,再通過schemePortResolver解析port,然后通過ConnectionSocketFactory創(chuàng)建socket,并根據(jù)socketConfig設(shè)置socket的參數(shù),最后執(zhí)行connectSocket,并綁定到conn
connectSocket
org/apache/http/conn/socket/PlainConnectionSocketFactory.java
public class PlainConnectionSocketFactory implements ConnectionSocketFactory { public static final PlainConnectionSocketFactory INSTANCE = new PlainConnectionSocketFactory(); public static PlainConnectionSocketFactory getSocketFactory() { return INSTANCE; } public PlainConnectionSocketFactory() { super(); } @Override public Socket createSocket(final HttpContext context) throws IOException { return new Socket(); } @Override public Socket connectSocket( final int connectTimeout, final Socket socket, final HttpHost host, final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpContext context) throws IOException { final Socket sock = socket != null ? socket : createSocket(context); if (localAddress != null) { sock.bind(localAddress); } try { sock.connect(remoteAddress, connectTimeout); } catch (final IOException ex) { try { sock.close(); } catch (final IOException ignore) { } throw ex; } return sock; } }
PlainConnectionSocketFactory的createSocket直接new一個socket,其connectSocket方法則執(zhí)行sock.connect
socketConfig
resolveSocketConfig
org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
private SocketConfig resolveSocketConfig(final HttpHost host) { SocketConfig socketConfig = this.configData.getSocketConfig(host); if (socketConfig == null) { socketConfig = this.configData.getDefaultSocketConfig(); } if (socketConfig == null) { socketConfig = SocketConfig.DEFAULT; } return socketConfig; }
PoolingHttpClientConnectionManager的resolveSocketConfig先是從configData根據(jù)指定host獲取socketConfig,若為null則再從configData獲取默認的socketConfig,若為null則返回默認的socketConfig
setSocketConfig
org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) { this.configData.setDefaultSocketConfig(defaultSocketConfig); } public void setSocketConfig(final HttpHost host, final SocketConfig socketConfig) { this.configData.setSocketConfig(host, socketConfig); }
PoolingHttpClientConnectionManager提供了setDefaultSocketConfig、setSocketConfig方法
SocketConfig.DEFAULT
org/apache/http/config/SocketConfig.java
public class SocketConfig implements Cloneable { public static final SocketConfig DEFAULT = new Builder().build(); //...... public static class Builder { private int soTimeout; private boolean soReuseAddress; private int soLinger; private boolean soKeepAlive; private boolean tcpNoDelay; private int sndBufSize; private int rcvBufSize; private int backlogSize; Builder() { this.soLinger = -1; this.tcpNoDelay = true; } //...... } }
默認的socketConfig,除了tcpNoDelay為true,其他的都為false,然后soLinger為-1
小結(jié)
HttpClientConnectionOperator定義了connect及upgrade方法,它有一個默認的實現(xiàn)類為DefaultHttpClientConnectionOperator;DefaultHttpClientConnectionOperator的connect先通過getSocketFactoryRegistry獲取Lookup<ConnectionSocketFactory>
,再通過它獲取ConnectionSocketFactory,之后通過dnsResolver解析地址,再通過schemePortResolver解析port,然后通過ConnectionSocketFactory創(chuàng)建socket,并根據(jù)socketConfig設(shè)置socket的參數(shù),最后執(zhí)行connectSocket,并綁定到conn;默認的socketConfig,除了tcpNoDelay為true,其他的都為false,然后soLinger為-1。
以上就是httpclient connect連接請求方法源碼解讀的詳細內(nèi)容,更多關(guān)于httpclient connect連接請求的資料請關(guān)注腳本之家其它相關(guān)文章!
- httpclient getPoolEntryBlocking連接池方法源碼解讀
- httpclient staleConnectionCheckEnabled獲取連接流程解析
- 解讀httpclient的validateAfterInactivity連接池狀態(tài)檢測
- httpclient的disableConnectionState方法工作流程
- 探索HttpClient中的close方法及其對連接的影響
- HttpClient的RedirectStrategy重定向處理核心機制
- HttpClient HttpRoutePlanner接口確定請求目標路由
- httpclient ConnectionHolder連接池連接保持源碼解析
相關(guān)文章
親測SpringBoot參數(shù)傳遞及@RequestBody注解---踩過的坑及解決
這篇文章主要介紹了親測SpringBoot參數(shù)傳遞及@RequestBody注解---踩過的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10Mybatis執(zhí)行流程、緩存原理及相關(guān)面試題匯總
最近剛學(xué)完MyBatis,趁著大好機會,總結(jié)一下它的執(zhí)行流程,面試也愛問這個,下面這篇文章主要給大家介紹了關(guān)于Mybatis執(zhí)行流程、緩存原理及相關(guān)面試題的相關(guān)資料,需要的朋友可以參考下2022-02-02Java簡單使用EasyExcel操作讀寫excel的步驟與要點
相信現(xiàn)在很多搞后端的同學(xué)大部分做的都是后臺管理系統(tǒng),那么管理系統(tǒng)就肯定免不了Excel的導(dǎo)出導(dǎo)入功能,下面這篇文章主要給大家介紹了關(guān)于Java簡單使用EasyExcel操作讀寫excel的步驟與要點,需要的朋友可以參考下2022-09-09