OkHttp3 -- 源码

《OkHttp3 -- 源码》

以get请求为例子:

  OkHttpClient client=new OkHttpClient();
  Request request=new Request.Builder().url("").build();
  Response response=client.newCall(request).execute();

三行代码就可以创建一个请求 , 接下来我们查看具体的代码

OkHttpClient client=new OkHttpClient();

public OkHttpClient() {
    this(new Builder());
  }

构造方法中再次调用有参的构造方法 , 点进去之后 , 会发现一系列的初始化操作 . 其中我们关心这几个属性 , 先记住名字就好

  • dispatcher 分发器
  • interceptors 应用层的拦截器
  • networkInterceptors 网络层拦截器

Request request=new Request.Builder().url(“”).build();

其实这里就是一个对象的初始化过程…….不多解释了

Response response=client.newCall(request).execute();

从newCall()方法开始:

@Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }

直接实例化了另一个类RealCall, 实例化之后 , 回到原来的语句中 , 接下来执行的execute()方法 , 就肯定是在该类中进行的了
这里不要直接点击execute , 会跑偏的= =

@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    try {
      // 使用分发器来处理
      client.dispatcher().executed(this);
      // 交由拦截器来处理
      Response result = getResponseWithInterceptorChain(false);
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

这里主要有两个方法 , 一个分发 , 一个拦截. 我们先看分发器的executed的实现:

synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

恩…….比较简单昂 , 就是将请求添加到队列中 , 这里用到队列数据结构. 加入队列之后, 拦截器来进一步处理

private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
  }

首先创建了一个应用层的拦截器ApplicationInterceptorChain , 再调用拦截器的proceed方法 , 获取到请求数据.
先点开ApplicationInterceptorChain , 发现它是一个内部类 , 初始化了一些东西 , 然后接下来的proceed方法也应该在这个类里面了

@Override public Response proceed(Request request) throws IOException {
      // If there's another interceptor in the chain, call that.
      if (index < client.interceptors().size()) {
        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
        Interceptor interceptor = client.interceptors().get(index);
        Response interceptedResponse = interceptor.intercept(chain);

        if (interceptedResponse == null) {
          throw new NullPointerException("application interceptor " + interceptor
              + " returned null");
        }

        return interceptedResponse;
      }

      // No more interceptors. Do HTTP.
      // 开始请求
      return getResponse(request, forWebSocket);
    }
  }

这里先判断了当前拦截器有没有对应的处理 , 没有就新建一个拦截器 , 并执行intercept方法 . 拦截器可以用来转换格式 , 重写请求等……最后 , 反回了真正的请求getResponse()

  Response getResponse(Request request, boolean forWebSocket) throws IOException {
    // Copy body metadata to the appropriate request headers.
    RequestBody body = request.body();

    // 拼接请求头
    if (body != null) {
      Request.Builder requestBuilder = request.newBuilder();

      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }

      request = requestBuilder.build();
    }

    // Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
    // 创建HTTP engine, 用于发送和回复的细节处理
    engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);

    int followUpCount = 0;
    while (true) {
      if (canceled) {
        engine.releaseStreamAllocation();
        throw new IOException("Canceled");
      }

      boolean releaseConnection = true;
      try {
        // 发送请求
        engine.sendRequest();

        // 读取回复
        engine.readResponse();
        releaseConnection = false;
      } catch (RequestException e) {
        // The attempt to interpret the request failed. Give up.
        throw e.getCause();
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        HttpEngine retryEngine = engine.recover(e.getLastConnectException(), true, null);
        if (retryEngine != null) {
          releaseConnection = false;
          engine = retryEngine;
          continue;
        }
        // Give up; recovery is not possible.
        throw e.getLastConnectException();
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        HttpEngine retryEngine = engine.recover(e, false, null);
        if (retryEngine != null) {
          releaseConnection = false;
          engine = retryEngine;
          continue;
        }

        // Give up; recovery is not possible.
        throw e;
      } finally {
        // We're throwing an unchecked exception. Release any resources.
        if (releaseConnection) {
          StreamAllocation streamAllocation = engine.close();
          streamAllocation.release();
        }
      }

      Response response = engine.getResponse();
      Request followUp = engine.followUpRequest();

      if (followUp == null) {
        if (!forWebSocket) {
          engine.releaseStreamAllocation();
        }
        return response;
      }

      StreamAllocation streamAllocation = engine.close();

      if (++followUpCount > MAX_FOLLOW_UPS) {
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }

      if (!engine.sameConnection(followUp.url())) {
        streamAllocation.release();
        streamAllocation = null;
      } else if (streamAllocation.stream() != null) {
        throw new IllegalStateException("Closing the body of " + response
            + " didn't close its backing stream. Bad interceptor?");
      }

      request = followUp;
      engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
          response);
    }
  }

首先 , 设置请求头 , 拼接一条完整的请求, 然后初始化HttpEngine用于细节优化 , 再开始请求 , 请求完成后读取请求结果.

  1. 开始请求部分:
 public void sendRequest() throws RequestException, RouteException, IOException {
    if (cacheStrategy != null) return; // Already sent.
    if (httpStream != null) throw new IllegalStateException();
    // 首先 ,对请求头再次做一次处理
    Request request = networkRequest(userRequest);
    // 获取用户设置的缓存
    InternalCache responseCache = Internal.instance.internalCache(client);
    // 从缓存中获取之前请求过的Response
    Response cacheCandidate = responseCache != null
        ? responseCache.get(request)
        : null;

    long now = System.currentTimeMillis();
     // 根据请求和缓存结果来设置缓存策略,先从缓存拿,如果超时,那么从网络请求.
    cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
    networkRequest = cacheStrategy.networkRequest;
    cacheResponse = cacheStrategy.cacheResponse;

    if (responseCache != null) {
      responseCache.trackResponse(cacheStrategy);
    }

    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
    }
...
...
try {
      // 建立链接, 使用socket创建,可以自动选择偏好链接, 选择连接时,首先从连接池来查找,
      // 没有的话使用路径选择器,若还找不到的话就新建一个连接,同时将连接放到连接池中
      httpStream = connect();
      httpStream.setHttpEngine(this);

      if (writeRequestHeadersEagerly()) {
        long contentLength = OkHeaders.contentLength(request);
        if (bufferRequestBody) {
          if (contentLength > Integer.MAX_VALUE) {
            throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
                + "setChunkedStreamingMode() for requests larger than 2 GiB.");
          }

          if (contentLength != -1) {
            // Buffer a request body of a known length.
            httpStream.writeRequestHeaders(networkRequest);
            requestBodyOut = new RetryableSink((int) contentLength);
          } else {
            // Buffer a request body of an unknown length. Don't write request headers until the
            // entire body is ready; otherwise we can't set the Content-Length header correctly.
            requestBodyOut = new RetryableSink();
          }
        } else {
          httpStream.writeRequestHeaders(networkRequest);
          requestBodyOut = httpStream.createRequestBody(networkRequest, contentLength);
        }
      }
      success = true;
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (!success && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
    原文作者:MinuitZ
    原文地址: https://www.jianshu.com/p/3243791be7eb
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞