OkHttp连接池源码追踪

本文深入探讨了OkHttp的连接池实现,从ConnectionPool的初始化开始,追踪RealCall的execute方法,揭示了责任链模式在处理请求中的关键作用。着重分析了RealInterceptorChain中的五大基础拦截器,尤其是RetryAndFollowUpInterceptor和ConnectInterceptor如何处理连接的获取与释放。最后,详细解释了ConnectionPool如何管理连接,包括连接的创建、回收和清理机制。
摘要由CSDN通过智能技术生成

1.先从构建OkHttpClient说起

重点看下ConnectionPool connectionPool = new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MINUTES);

public class OkHttpUtil {
    private static final Logger logger = LoggerFactory.getLogger(OkHttpClient.class);
    private static final String MEDIA_TYPE_JSON = "application/json; charset=utf-8";
    private static final String CHAR_NULL = "";

    private static class OkHttpUtilHolder {
        private static final OkHttpUtil INSTANCE = new OkHttpUtil();
    }

    public static OkHttpUtil getIntance() {
        return OkHttpUtilHolder.INSTANCE;
    }

    private OkHttpUtil() {
    }


    private static OkHttpClient okHttpClient;
    private static boolean okHttpLogSwitch;
    static OkHttpClient.Builder builder = new OkHttpClient().newBuilder();

    static {
        int maxIdleConnections = PropertiesUtil.getProperty(OKHTTP_POOL_MAXIDLECONNECTIONS) != null ? Integer.parseInt(PropertiesUtil.getProperty(OKHTTP_POOL_MAXIDLECONNECTIONS)) : DEFAULT_CLIENT_MAXIDLECONNECTIONS;
        long keepAliveDuration = PropertiesUtil.getProperty(OKHTTP_POOL_KEEPALIVEDURATION) != null ? Long.parseLong(PropertiesUtil.getProperty(OKHTTP_POOL_KEEPALIVEDURATION)) : DEFAULT_CLIENT_KEEPALIVEDURATION;
        long connectTimeout = PropertiesUtil.getProperty(OKHTTP_CLIENT_CONNECTTIMEOUT) != null ? Long.parseLong(PropertiesUtil.getProperty(OKHTTP_CLIENT_CONNECTTIMEOUT)) : DEFAULT_CLIENT_CONNECTTIMEOUT;
        long writeTimeout = PropertiesUtil.getProperty(OKHTTP_CLIENT_WRITETIMEOUT) != null ? Long.parseLong(PropertiesUtil.getProperty(OKHTTP_CLIENT_WRITETIMEOUT)) : DEFAULT_CLIENT_WRITETIMEOUT;
        long readTimeout = PropertiesUtil.getProperty(OKHTTP_CLIENT_READTIMEOUT) != null ? Long.parseLong(PropertiesUtil.getProperty(OKHTTP_CLIENT_READTIMEOUT)) : DEFAULT_CLIENT_READTIMEOUT;
        int maxRetry = PropertiesUtil.getProperty(OKHTTP_CLIENT_MAXRETRY) != null ? Integer.parseInt(PropertiesUtil.getProperty(OKHTTP_CLIENT_MAXRETRY)) : DEFAULT_CLIENT_MAXRETRY;
        okHttpLogSwitch = PropertiesUtil.getProperty(OKHTTP_CLIENT_LOGSWITCH) != null ? Boolean.parseBoolean(PropertiesUtil.getProperty(OKHTTP_CLIENT_LOGSWITCH)) : DEFAULT_CLIENT_LOGSWITCH;
        boolean logParamsSwitch = PropertiesUtil.getProperty(OKHTTP_CLIENT_LOGPARAMSSWITCH) != null ? Boolean.parseBoolean(PropertiesUtil.getProperty(OKHTTP_CLIENT_LOGPARAMSSWITCH)) : DEFAULT_CLIENT_LOGSWITCH;
        boolean enableHttps = PropertiesUtil.getProperty(OKHTTP_CLIENT_ENABLEHTTPS) != null ? Boolean.parseBoolean(PropertiesUtil.getProperty(OKHTTP_CLIENT_ENABLEHTTPS)) : DEFAULT_CLIENT_ENABLEHTTPS;
        String timeUnit = PropertiesUtil.getProperty(OKHTTP_CLIENT_TIMEUNIT);
        ConnectionPool connectionPool = new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MINUTES);
        builder.connectionPool(connectionPool)
                .retryOnConnectionFailure(true)
                .addInterceptor(new RetryIntercepter(maxRetry, okHttpLogSwitch, logParamsSwitch));

        if (timeUnit != null && timeUnit.equals(DEFAULT_CLIENT_TIMEUNIT_MS)) {
            builder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
                    .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
                    .readTimeout(readTimeout, TimeUnit.MILLISECONDS);
        } else {
            builder.connectTimeout(connectTimeout, TimeUnit.SECONDS)
                    .writeTimeout(writeTimeout, TimeUnit.SECONDS)
                    .readTimeout(readTimeout, TimeUnit.SECONDS);
        }
        if (enableHttps) {
            trustAllHosts();//璁剧疆蹇界暐瀹夊叏璇佷功楠岃瘉
            // 瀹炵幇HostnameVerifier鎺ュ彛锛屼笉杩涜url鍜屾湇鍔″櫒涓绘満鍚嶇殑楠岃瘉銆�
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {

                    return true;
                }
            });
        }
        okHttpClient = builder.build();
    }


    public OkResponseResult doGet(OkHttpRequest okHttpRequest) {
        Headers.Builder headerBuilder = buildHeaders(okHttpRequest.headerParams(), okHttpRequest.retryTimes(), okHttpRequest.reqLogIgnore());
        long startNanoTime = nanoTime();
        boolean success = true;
        String tag = swapTag(okHttpRequest.tag());
        Request request = new Request.Builder().headers(headerBuilder.build()).url(okHttpRequest.url()).tag(tag).build();
        Call call = okHttpClient.newCall(request);
        Response execute = null;
        try {
            execute = call.execute();
            if (execute != null && execute.isSuccessful()) {
                return OkResponseResult.buildSuccessResponse(execute);
            }
            success = false;
            return OkResponseResult.buildFaliureResponse(execute);
        } catch (Exception e) {
            logger.error(GET_ERROR_MSG, e);
            if (execute != null && execute.body() != null) {
                execute.body().close();
            }
            success = false;
            return OkResponseResult.buildIOExceptionResponse();
        } finally {
            long micros = NANOSECONDS.toMicros(nanoTime() - startNanoTime);
            PerfUtils.perf(success ? "http.success" : "http.fail", getBizName(), getIdentity(okHttpRequest))
                    .micros(micros)
                    .logstashOnly();
        }
    }
}

2.RealCall类是OkHttp的核心类

Call call = okHttpClient.newCall(request);

execute = call.execute();

final class RealCall implements Call {
  final OkHttpClient client;
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;

  /**
   * There is a cycle between the {@link Call} and {@link EventListener} that makes this awkward.
   * This will be set after we create the call instance then create the event listener instance.
   */
  private EventListener eventListener;

  /** The application's original request unadulterated by redirects or auth headers. */
  final Request originalRequest;
  final boolean forWebSocket;

  // Guarded by this.
  private boolean executed;

  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }

  @Override public Request request()
Java的OkHttp库是一个用于发送HTTP请求的强大工具,它支持HTTP/2、连接池、GZIP压缩响应等特性。连接池OkHttp中的一个重要特性,它能够减少网络延迟,提高应用程序性能。 在OkHttp中,连接池用于维护和复用到同一服务器的TCP连接。当你的应用程序需要与服务器通信时,OkHttp首先会检查连接池中是否有可用的连接。如果有,OkHttp会复用该连接来发送请求,这样可以减少三次握手的开销,提高了网络请求的效率。 OkHttp连接池是通过`ConnectionPool`类来实现的。默认情况下,OkHttp使用一个具有5个最大空闲连接的连接池,这些连接在5分钟无活动后会被清理。你可以通过`ConnectionPool`构造器自定义这些参数,以适应你的应用程序需求。 以下是连接池的一些关键特性: 1. **最大空闲连接数**:决定连接池中最多可以有多少个空闲连接。过多的空闲连接可能会占用过多资源。 2. **空闲连接超时时间**:指定一个连接多久没有使用就会被关闭。这有助于避免因长时间闲置而占用系统资源。 3. **保持活动时间**:对于每个路由,OkHttp会保持至少一个空闲连接在指定的时间内活动。 使用自定义的`ConnectionPool`时,可以按照以下方式进行配置: ```java int maxIdleConnections = 5; // 最大空闲连接数 long keepAliveDuration = 5; // 连接保持活动的时间,单位为分钟 ConnectionPool connectionPool = new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MINUTES); OkHttpClient client = new OkHttpClient.Builder() .connectionPool(connectionPool) .build(); ``` 通过这种方式,你可以有效地管理应用程序中的HTTP连接,并提高应用的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值