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;
}