Okhttp源码分析记录(一)

背景

Android开发中会用到各种各样的框架,熟悉框架的原理是进阶中必不可少的部分,然而只是跟着源码走一遍,很容易就遗忘了,所以想到了用博客来记录分析的过程,当然写博客时候也必定会查阅大量资料,这对框架的分析是有好处的。

okhttp是目前主流的网络请求框架,retrofit的内嵌的网络请求也是使用okhttp进行的。本文主要研究okhttp的源码流程与相关知识。也会记录自己阅读源码的一些姿势。

实际场景

源码的入口应该从常用的地方着手。下图为okhttp实际使用的情景。

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
     .url("url")
     .addHeader("user_agent","tongZhang")
     .build(); 
Call call = client.newCall(request);
call.enqueue(new Callback() {
     @Override
     public void onFailure(Call call, IOException e) {

     }
     @Override
     public void onResponse(Call call, Response response) 
throws IOException {

            }
        });
源码分析

首先创建OkHttpClient的实例,点进去看看。发现采用了Builder模式进行OkHttpClient相关属性的初始化。

  public static final class Builder {
    Dispatcher dispatcher;
    @Nullable Proxy proxy;
    List protocols;
    List connectionSpecs;
    final List interceptors = new ArrayList<>();
    final List networkInterceptors = new ArrayList<>();
    EventListener.Factory eventListenerFactory;
    ProxySelector proxySelector;
    CookieJar cookieJar;
    @Nullable Cache cache;
    @Nullable InternalCache internalCache;
    SocketFactory socketFactory;
    @Nullable SSLSocketFactory sslSocketFactory;
    @Nullable CertificateChainCleaner certificateChainCleaner;
    HostnameVerifier hostnameVerifier;
    CertificatePinner certificatePinner;
    Authenticator proxyAuthenticator;
    Authenticator authenticator;
    ConnectionPool connectionPool;
    Dns dns;
    boolean followSslRedirects;
    boolean followRedirects;
    boolean retryOnConnectionFailure;
    int connectTimeout;
    int readTimeout;
    int writeTimeout;
    int pingInterval;

这里只需要大概了解每个属性的作用就可以了,有的变量从命名就可以了解它的含义,有的变量类需要点进去看到它的具体作用,一些注释也会帮助我们了解。

Dispatcher不明白,点进去。

/**
 * Policy on when async requests are executed.
 *
 * 

Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your * own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number * of calls concurrently. */ public final class Dispatcher { private int maxRequests = 64; private int maxRequestsPerHost = 5; private @Nullable Runnable idleCallback; /** Executes calls. Created lazily. */ private @Nullable ExecutorService executorService; /** Ready async calls in the order they'll be run. */ private final Deque readyAsyncCalls = new ArrayDeque<>(); /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque runningAsyncCalls = new ArrayDeque<>(); /** Running synchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque runningSyncCalls = new ArrayDeque<>();

上面的英文注释看不懂可以借助翻译,大概意思是 当异步请求执行时。再大概瞄几眼这个类的属性和方法。发现了它是跟请求相关的,还出现了一些ThreadPoolExecutro的东西,不管了,知道它大体是负责异步请求执行相关的东西就好了。

Proxy,点进去发现是一些请求类型,不过在new Builder中没找到proxy的赋值,不管了。

/**
 * This class represents a proxy setting, typically a type (http, socks) and
 * a socket address.
 * A {@code Proxy} is an immutable object.
 *
 * @see     java.net.ProxySelector
 * @author Yingxian Wang
 * @author Jean-Christophe Collet
 * @since   1.5
 */
public class Proxy {

    /**
     * Represents the proxy type.
     *
     * @since 1.5
     */
    public enum Type {
        /**
         * Represents a direct connection, or the absence of a proxy.
         */
        DIRECT,
        /**
         * Represents proxy for high level protocols such as HTTP or FTP.
         */
        HTTP,
        /**
         * Represents a SOCKS (V4 or V5) proxy.
         */
        SOCKS
    };

大概就这么分析下来会知道
protocols是一些http版本的头信息集合。
connectionSpecs是HTTP套接字连接的配置集合。
interceptors是Interceptor的集合,从英文注释上了解到是拦截器,大概就是修改请求头和反馈一些响应。

/**
 * Observes, modifies, and potentially short-circuits requests going out and the corresponding
 * responses coming back in. Typically interceptors add, remove, or transform headers on the request
 * or response.
 */
public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

networkInterceptors跟interceptors类似,从字面意思理解是跟网络相关的拦截器集合。
eventListenerFactory从字面上像是个监听器。点进去看看。

 eventListenerFactory = EventListener.factory(EventListener.NONE);
public abstract class EventListener {
  public static final EventListener NONE = new EventListener() {
  };

  static EventListener.Factory factory(final EventListener listener) {
    return new EventListener.Factory() {
      public EventListener create(Call call) {
        return listener;
      }
    };
  }

结合代码与英文注释分析确实是获得了个初始化后的Factory接口,一旦执行create就会获得这个监听器,call大概是请求,由请求来得到一个监听,感觉也蛮合适的。

ProxySelector是proxy(上面已经分析过了)的选择器。

CooKieJar不会是服务器那边cookie session那个东西吧?

public interface CookieJar {
  /** A cookie jar that never accepts any cookies. */
  CookieJar NO_COOKIES = new CookieJar() {
    @Override public void saveFromResponse(HttpUrl url, List cookies) {
    }

    @Override public List loadForRequest(HttpUrl url) {
      return Collections.emptyList();
    }
  };

没准还真是,这里默认是选择不接受任何cookie。

socketFactory是socket工厂,负责生产socket,源码也简单,我就不贴了,太占篇幅了。
hostnameVerifier貌似是一些认证,http的握手认证。(分析英文注释)
cettificatePinner是一些证书的管理。还是握手协议那块的东西。(分析英文注释)
proxyAuthenticator和authenticator是对请求头的一些反馈。(分析英文注释)

 * <p>When authentication is requested by an origin server, the response code is 401 and the
 * implementation should respond with a new request that sets the "Authorization" header.
 * <pre>   {@code
 *
 *    if (response.request().header("Authorization") != null) {
 *      return null; // Give up, we've already failed to authenticate.
 *    }
 *
 *    String credential = Credentials.basic(...)
 *    return response.request().newBuilder()
 *        .header("Authorization", credential)
 *        .build();
 * }</pre>
 *
 * <p>When authentication is requested by a proxy server, the response code is 407 and the
 * implementation should respond with a new request that sets the "Proxy-Authorization" header.
 * <pre>   {@code
 *
 *    if (response.request().header("Proxy-Authorization") != null) {
 *      return null; // Give up, we've already failed to authenticate.
 *    }
 *
 *    String credential = Credentials.basic(...)
 *    return response.request().newBuilder()
 *        .header("Proxy-Authorization", credential)
 *        .build();

connectionPool是连接池,当前容纳五个空闲的连接,存活时间是五分钟。

   * Create a new connection pool with tuning parameters appropriate for a single-user application.
   * The tuning parameters in this pool are subject to change in future OkHttp releases. Currently
   * this pool holds up to 5 idle connections which will be evicted after 5 minutes of inactivity.
   */
  public ConnectionPool() {
    this(5, 5, TimeUnit.MINUTES);
  }

  public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
    this.maxIdleConnections = maxIdleConnections;
    this.keepAliveDurationNs = timeUnit.toNanos(keepAliveDuration);

    // Put a floor on the keep alive duration, otherwise cleanup will spin loop.
    if (keepAliveDuration <= 0) {
      throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration);
    }
  }

dns大家应该不陌生,是映射ip与域名的服务器。属于网络相关的一个属性。

剩下一些基本类型,顾名思义,思不到意也没关系。

      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;

OkHttpClient的所有属性先摸上一遍,不用深入分析,知道各自的用处就好了,后续的分析还会再次用到这些属性,前面的分析只是方便后面源码的分析。

接着最初的入口分析。OkHttpClient的实例创建完了,接着又创建了request请求的实例。

        Request request = new Request.Builder()
                .url("url")
                .addHeader("user_agent","tongZhang")
                .build();

这个就不需要分析了,简单的Builder模式,封装成一个请求类的实例。

接着看。

        Call call = client.newCall(request);

点进去。

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

创建了一个RealCall的实例,点进去看构造方法,发现只是赋值了相关属性,并初始化了一个名为RetryAndFollowUpInterceptor的拦截器。

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);
  }

返回上图会发现之前分析的eventListener出现了。

    call.eventListener = client.eventListenerFactory().create(call);

根据之前的分析确实是由这个创建的RealCall的实例create生成了eventListener监听器。

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

这个call实际上就是RealCall执行enqueue方法。

  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

首先判断executed是否执行过,若是执行过就抛异常,确保执行一次。captureCallStackTrace方法看名字是捕捉调用栈的信息。

  private void captureCallStackTrace() {
    Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
  }

Platform.get得到Android平台,再点进getStackTraceForCloseable方法,根据英文注释了解此方法会返回一些堆栈跟踪的信息。将此信息赋值给retryAndFollowUpInterceptor,至于为什么这么做,先往后看。

    eventListener.callStart(this);

监听器执行callStart方法,关于监听器更详细的内容可以点进去详细分析下,这里不做深入。继续看。

    client.dispatcher().enqueue(new AsyncCall(responseCallback));

responseCallback是开放给我们定义的回调接口,这里通过new AsyncCall进行封装。

  final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

进入dispatcher的enqueue方法。

  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

根据注释和代码分析得知,runningAsyncCalls是正在运行的异步请求队列。runningCallsForHost(call)是跟此call相同的host的数量,意思就是当前正在运行的异步请求队列小于64,并且相同host请求数量小于5就先执行add.后执行execute。如果请求过多,则加入readyAsync队列待命。

  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

继续分析executorService方法。发现这里会通过线程池来执行异步请求。执行AsyncCall。

    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

重点是这个getResponseWithInterceptorChain()返回Response了,后面的判断是为了执行相关回调接口与监听器的回调方法。
getResponseWithInterceptorChain是通过拦截器链得到response,这个下一篇会讲到。

你可能感兴趣的:(源码分析,Android,okhttp,源码分析)