public CloseableHttpClient build() { //省略部分代码 HttpClientConnectionManager connManagerCopy = this.connManager; //如果指定了连接池管理器则使用指定的,否则新建一个默认的 if (connManagerCopy == null) { LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory; if (sslSocketFactoryCopy == null) { //如果开启了使用环境变量,https版本与密码控件从环境变量中读取 final String[] supportedProtocols = systemProperties ? split( System.getProperty("https.protocols")) : null; final String[] supportedCipherSuites = systemProperties ? split( System.getProperty("https.cipherSuites")) : null; //如果没有指定,使用默认的域名验证器,会根据ssl会话中服务端返回的证书来验证与域名是否匹配 HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier; if (hostnameVerifierCopy == null) { hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy); } //如果制定了SslContext则生成定制的SSL连接工厂,否则使用默认的连接工厂 if (sslContext != null) { sslSocketFactoryCopy = new SSLConnectionSocketFactory( sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy); } else { if (systemProperties) { sslSocketFactoryCopy = new SSLConnectionSocketFactory( (SSLSocketFactory) SSLSocketFactory.getDefault(), supportedProtocols, supportedCipherSuites, hostnameVerifierCopy); } else { sslSocketFactoryCopy = new SSLConnectionSocketFactory( SSLContexts.createDefault(), hostnameVerifierCopy); } } } //将Ssl连接工厂注册到连接池管理器中,当需要产生Https连接的时候,会根据上面的SSL连接工厂生产SSL连接 @SuppressWarnings("resource") final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager( RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslSocketFactoryCopy) .build(), null, null, dnsResolver, connTimeToLive, connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS); //省略部分代码 } }
public void connect( final ManagedHttpClientConnection conn, final HttpHost host, final InetSocketAddress localAddress, final int connectTimeout, final SocketConfig socketConfig, final HttpContext context) throws IOException { //之前在HttpClientBuilder中register了http与https不同的连接池实现,这里lookup获得Https的实现,即SSLConnectionSocketFactory 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"); } //如果是ip形式的地址可以直接使用,否则使用dns解析器解析得到域名对应的ip final InetAddress[] addresses = host.getAddress() != null ? new InetAddress[] { host.getAddress() } : this.dnsResolver.resolve(host.getHostName()); final int port = this.schemePortResolver.resolve(host); //一个域名可能对应多个Ip,按照顺序尝试连接 for (int i = 0; i < addresses.length; i ) { final InetAddress address = addresses[i]; final boolean last = i == addresses.length - 1; //这里只是生成一个socket,还并没有连接 Socket sock = sf.createSocket(context); //设置一些tcp层的参数 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 { //通过SSLConnectionSocketFactory建立连接并绑定到conn上 sock = sf.connectSocket( connectTimeout, sock, host, remoteAddress, localAddress, context); conn.bind(sock); if (this.log.isDebugEnabled()) { this.log.debug("Connection established " conn); } return; } //省略一些代码 } }
@Override public Socket connectSocket( final int connectTimeout, final Socket socket, final HttpHost host, final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpContext context) throws IOException { Args.notNull(host, "HTTP host"); Args.notNull(remoteAddress, "Remote address"); final Socket sock = socket != null ? socket : createSocket(context); if (localAddress != null) { sock.bind(localAddress); } try { if (connectTimeout > 0 && sock.getSoTimeout() == 0) { sock.setSoTimeout(connectTimeout); } if (this.log.isDebugEnabled()) { this.log.debug("Connecting socket to " remoteAddress " with timeout " connectTimeout); } //建立连接 sock.connect(remoteAddress, connectTimeout); } catch (final IOException ex) { try { sock.close(); } catch (final IOException ignore) { } throw ex; } // 如果当前是SslSocket则进行SSL握手与域名校验 if (sock instanceof SSLSocket) { final SSLSocket sslsock = (SSLSocket) sock; this.log.debug("Starting handshake"); sslsock.startHandshake(); verifyHostname(sslsock, host.getHostName()); return sock; } else { //如果不是SslSocket则将其包装为SslSocket return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context); } } @Override public Socket createLayeredSocket( final Socket socket, final String target, final int port, final HttpContext context) throws IOException { //将普通socket包装为SslSocket,socketfactory是根据HttpClientBuilder中的SSLContext生成的,其中包含密钥信息 final SSLSocket sslsock = (SSLSocket) this.socketfactory.createSocket( socket, target, port, true); //如果制定了SSL层协议版本与加密算法,则使用指定的,否则使用默认的 if (supportedProtocols != null) { sslsock.setEnabledProtocols(supportedProtocols); } else { // If supported protocols are not explicitly set, remove all SSL protocol versions final String[] allProtocols = sslsock.getEnabledProtocols(); final List<String> enabledProtocols = new ArrayList<String>(allProtocols.length); for (final String protocol: allProtocols) { if (!protocol.startsWith("SSL")) { enabledProtocols.add(protocol); } } if (!enabledProtocols.isEmpty()) { sslsock.setEnabledProtocols(enabledProtocols.toArray(new String[enabledProtocols.size()])); } } if (supportedCipherSuites != null) { sslsock.setEnabledCipherSuites(supportedCipherSuites); } if (this.log.isDebugEnabled()) { this.log.debug("Enabled protocols: " Arrays.asList(sslsock.getEnabledProtocols())); this.log.debug("Enabled cipher suites:" Arrays.asList(sslsock.getEnabledCipherSuites())); } prepareSocket(sslsock); this.log.debug("Starting handshake"); //Ssl连接握手 sslsock.startHandshake(); //握手成功后校验返回的证书与域名是否一致 verifyHostname(sslsock, target); return sslsock; }