OkHttp3(十三)--ConnectInterceptor

ConnectInterceptor

与服务端建立连接,并且获得通向服务端的输入和输出流对象

  • 创建输入输出流
  • 建立连接
  • 执行下一个拦截器

ConnectInterceptor部分源码

  @Override 
  public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    StreamAllocation streamAllocation = realChain.streamAllocation();

    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    //创建输出流
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    //获取连接
    RealConnection connection = streamAllocation.connection();
    //执行下一个拦截器
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }

StreamAllocation.newStream()

newStream()方法主要做了如下的工作

    1. 从缓冲池ConnectionPool获取一个RealConnection对象,如果缓冲池里面没有就创建一个RealConnection对象并且放入缓冲池中,具体的说是放入ConnectionPool的ArrayDeque队列中
    1. 获取RealConnection对象后并调用其connect打开Socket链接
  public HttpCodec newStream(
      OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {

    ...

    try {
      //获取一个RealConnection对象(在连接池中寻找或者在新创建一个连接)
      RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
          writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
      //获取HttpCodec 对象
      HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
      //返回HttpCodec对象
      synchronized (connectionPool) {
        codec = resultCodec;
        return resultCodec;
      }
    } catch (IOException e) {
      throw new RouteException(e);
    }
  }

1、调用findHealthyConnection获取一个RealConnection对象
2、通过获取到的RealConnection来生成一个HttpCodec对象并返回

StreamAllocation. findHealthyConnection()

  private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
      int writeTimeout, int pingIntervalMillis, boolean connectionRetryEnabled,
      boolean doExtensiveHealthChecks) throws IOException {
    while (true) {
      //获取RealConnection对象
      RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
          pingIntervalMillis, connectionRetryEnabled);
      //如果这个连接是新的连接,那么不需要进行可用新检查了,直接返回这个新的的连接
      synchronized (connectionPool) {
        if (candidate.successCount == 0) {
          return candidate;
        }
      }
      //这个连接是从连接池中取出的,检测是否可用
      if (!candidate.isHealthy(doExtensiveHealthChecks)) {
        //不可用关闭这个连接,从新寻找
        noNewStreams();
        continue;
      }
      return candidate;
    }
  }

1、开启一个while循环,调用findConnection继续获取RealConnection对象candidate 。
2、如果candidate 的successCount 为0,直接返回之,while循环结束
3、如果candidate是一个不“健康”的对象,则对此对象进行调用noNewStreams进行销毁处理,继续循环调用findConnection获取RealConnection对象。
(注:不健康的RealConnection条件为如下几种情况: RealConnection对象 socket没有关闭 ,socket的输入流没有关闭 ,socket的输出流没有关闭 ,http2时连接没有关闭 )

StreamAllocation. findConnection()

  private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
      int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
    boolean foundPooledConnection = false;
    RealConnection result = null;
    Route selectedRoute = null;
    Connection releasedConnection;
    Socket toClose;
    synchronized (connectionPool) {
      if (released) throw new IllegalStateException("released");
      if (codec != null) throw new IllegalStateException("codec != null");
      if (canceled) throw new IOException("Canceled");

      releasedConnection = this.connection;
      //释放不可复用的connection
      toClose = releaseIfNoNewStreams();
      if (this.connection != null) {
        //尝试复用
        result = this.connection;
        releasedConnection = null;
      }
      if (!reportedAcquired) {
        releasedConnection = null;
      }

      if (result == null) {
        Internal.instance.get(connectionPool, address, this, null);
        if (connection != null) {
          foundPooledConnection = true;
          result = connection;
        } else {
          selectedRoute = route;
        }
      }
    }
    closeQuietly(toClose);

    if (releasedConnection != null) {
      eventListener.connectionReleased(call, releasedConnection);
    }
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
    }
    if (result != null) {
      //可以复用直接返回
      return result;
    }
    boolean newRouteSelection = false;
    //阻塞操作
    if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) {
      newRouteSelection = true;
      routeSelection = routeSelector.next();
    }

    synchronized (connectionPool) {
      if (canceled) throw new IOException("Canceled");
      if (newRouteSelection) {
        List routes = routeSelection.getAll();
        for (int i = 0, size = routes.size(); i < size; i++) {
          Route route = routes.get(i);
          //从缓冲池中获取对象
          Internal.instance.get(connectionPool, address, this, route);
          //缓存池中有此连接
          if (connection != null) {
            foundPooledConnection = true;
            result = connection;
            this.route = route;
            break;
          }
        }
      }
      //缓存池中没有此连接,初始化一个 
      if (!foundPooledConnection) {
        if (selectedRoute == null) {
          selectedRoute = routeSelection.next();
        }
        route = selectedRoute;
        refusedStreamCount = 0;
        //初始化
        result = new RealConnection(connectionPool, selectedRoute);
        //将当前StreamAllocation的弱引用
        //交给result的allocations集合里
        //并将result赋值给this.connection这个引用
        acquire(result, false);
      }
    }
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
      return result;
    }

    //开始Socket连接,为阻塞操作
    result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
        connectionRetryEnabled, call, eventListener);
    routeDatabase().connected(result.route());

    Socket socket = null;
    synchronized (connectionPool) {
      reportedAcquired = true;

      //将新创建的RealConection放入到缓冲池
      Internal.instance.put(connectionPool, result);

      if (result.isMultiplexed()) {
        socket = Internal.instance.deduplicate(connectionPool, address, this);
        result = connection;
      }
    }
    closeQuietly(socket);

    eventListener.connectionAcquired(call, result);
    return result;
  }

结合代码中的注释,这个类大体上做了如下几个工作:
1、StreamAllocation的connection能复用就复用之
2、如果connection不能复用,则从连接池中获取RealConnection,获取成功则返回
3,如果连接池里没有则new一个RealConnection对象,并放入连接池中
4.最终调用RealConnection的connect方法打开一个socket链接

总的来说ConnectionInterceptor就是弄一个RealConnection对象,然后创建Socket链接,并且调用下一个也是最后一个拦截器来完成OkHttp的整个操作。

你可能感兴趣的:(OkHttp3(十三)--ConnectInterceptor)