httpClient连接池创建逻辑:
- org.springframework.boot.web.client.ClientHttpRequestFactorySupplier
我们知道restTemplate只是一个模板类,具体的httpClent还是需要各种jar包类提供,下面的类就是一个选择httpClient的具体实现过程,以及创建对应的工厂类:
// ClientHttpRequestFactory的供应商,根据类路径上的可用实现检测首选候选
public class ClientHttpRequestFactorySupplier implements Supplier {
private static final Map REQUEST_FACTORY_CANDIDATES;
static {
Map candidates = new LinkedHashMap<>();
candidates.put("org.apache.http.client.HttpClient","org.springframework.http.client.HttpComponentsClientHttpRequestFactory");
candidates.put("okhttp3.OkHttpClient","org.springframework.http.client.OkHttp3ClientHttpRequestFactory");
REQUEST_FACTORY_CANDIDATES = Collections.unmodifiableMap(candidates);
}
@Override
public ClientHttpRequestFactory get() {
for (Map.Entry candidate : REQUEST_FACTORY_CANDIDATES.entrySet()) {
ClassLoader classLoader = getClass().getClassLoader();
if (ClassUtils.isPresent(candidate.getKey(), classLoader)) {
Class> factoryClass = ClassUtils.resolveClassName(candidate.getValue(), classLoader);
return (ClientHttpRequestFactory) BeanUtils.instantiateClass(factoryClass);
}
}
return new SimpleClientHttpRequestFactory();
}
}
此类通过定义好的类路径去寻找最优的httpClient提供商,分别按顺序通过反射去筛选是否能找到apache.httpClient和okhttp的类,如果能找到apache.httpClient则去实例化对应的ClientHttpRequestFactory类,如果都找不到则创建默认的SimpleClientHttpRequestFactory类,此工厂中使用了默认的jdk.net包。对应的okhttp也有自己的工厂类OkHttp3ClientHttpRequestFactory。
- org.springframework.http.client.HttpComponentsClientHttpRequestFactory:74
/**
* 根据系统属性,使用默认的HttpClient创建HttpComponentsClientHttpRequestFactory的新实例
* Create a new instance of the {@code HttpComponentsClientHttpRequestFactory}
* with a default {@link HttpClient} based on system properties.
*/
public HttpComponentsClientHttpRequestFactory() {
this.httpClient = HttpClients.createSystem();
}
此类是spring为restTemplate提供的类,满足了restTemplate使用HttpClient的需求
构造方法中调用了HttpClient的createSystem方法创建一个HttpClent实体,此构造方法在spring实例化restTemplate时会被调用。
- org.apache.http.impl.client.HttpClients:63
/**
* 使用基于系统属性的默认配置创建CloseableHttpClient实例
* Creates {@link CloseableHttpClient} instance with default
* configuration based on system properties.
*/
public static CloseableHttpClient createSystem() {
return HttpClientBuilder.create().useSystemProperties().build();
}
此类是httpClient提供的工厂方法类,提供了多种创建httpClient实例的工厂方法
调用了HttpClientBuilder的create()方法,默认使用系统属性,调用了useSystemProperties()方法
- org.apache.http.impl.client.HttpClientBuilder
public static HttpClientBuilder create() {
return new HttpClientBuilder();
}
// 在创建和配置默认实现时使用系统属性
public final HttpClientBuilder useSystemProperties() {
this.systemProperties = true;
return this;
}
此类是CloseableHttpClient实例的构建器
其中最主的是build()方法,对各种参数进行了设置,其中一些重要部分的设置代码如下所示:
:
// 连接池初始化 调用PoolingHttpClientConnectionManager构造方法创建连接池
final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactoryCopy)
.build(),
null,
null,
dnsResolver,
connTimeToLive,
connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
if (defaultSocketConfig != null) {
poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
}
if (defaultConnectionConfig != null) {
poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
}
// httpClient默认连接数量的设置
// 其中systemProperties参数代表创建的httpClient是否使用系统属性,在上面的useSystemProperties()方法中设置为true
// 如果 http.keepAlive(默认值为true) 为true,则会将 http.maxConnections(默认值为5) 属性的值设置为同一个路由最多可以使用的连接数,而连接池的最大连接数量为同一个路由最多使用连接数量的两倍
if (systemProperties) {
String s = System.getProperty("http.keepAlive", "true");
if ("true".equalsIgnoreCase(s)) {
s = System.getProperty("http.maxConnections", "5");
final int max = Integer.parseInt(s);
poolingmgr.setDefaultMaxPerRoute(max);
poolingmgr.setMaxTotal(2 * max);
}
}
if (maxConnTotal > 0) {
poolingmgr.setMaxTotal(maxConnTotal);
}
if (maxConnPerRoute > 0) {
poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
}
connManagerCopy = poolingmgr;
org.apache.http.impl.conn.PoolingHttpClientConnectionManager
public PoolingHttpClientConnectionManager(
final Registry socketFactoryRegistry,
final HttpConnectionFactory connFactory,
final SchemePortResolver schemePortResolver,
final DnsResolver dnsResolver,
final long timeToLive, final TimeUnit timeUnit) {
this(
new DefaultHttpClientConnectionOperator(socketFactoryRegistry,
schemePortResolver, dnsResolver),
connFactory,
timeToLive, timeUnit
);
}
// 真正创建创建连接池的构造方法
public PoolingHttpClientConnectionManager(
final HttpClientConnectionOperator httpClientConnectionOperator,
final HttpConnectionFactory connFactory,
final long timeToLive, final TimeUnit timeUnit) {
super();
this.configData = new ConfigData();
// 设置默认每个路由最大使用两个连接,连接池总共有20个连接
this.pool = new CPool(new InternalConnectionFactory(this.configData, connFactory), 2, 20, timeToLive, timeUnit);
this.pool.setValidateAfterInactivity(2000);
this.connectionOperator = Args.notNull(httpClientConnectionOperator, "HttpClientConnectionOperator");
this.isShutDown = new AtomicBoolean(false);
}
org.apache.http.impl.conn.DefaultHttpClientConnectionOperator:
public DefaultHttpClientConnectionOperator(
final Lookup 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;
}