reatTemplate->httpClient连接池创建逻辑

httpClient连接池创建逻辑:

  1. 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。

  1. 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时会被调用。

  1. 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()方法

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


你可能感兴趣的:(reatTemplate->httpClient连接池创建逻辑)