OkHttp3 源码解析

OkHttp3 源码解析

相关参考:

《Android进阶之光》

https://www.jianshu.com/p/37e26f4ea57b

https://juejin.im/entry/597800116fb9a06baf2eeb63

https://juejin.im/post/5af4482951882567286064e6
本文是基于OkHttp 3.10.0 所作分析

同步请求源码分析

Request request = new Request.Builder().url("https://raw.github.com/square/okhttp/master/README.md").method("GET", null).build();
Call call = mOkHttpClient.newCall(request);
Response response = null;
try {
    response = call.execute();// 同步
} catch (IOException e) {
    e.printStackTrace();
}
if (response != null) {
    Log.d(TAG, "testGet() response = " + response);
} else {
    Log.d(TAG, "testGet() response == null");
}

创建OkHttpClient

上述就是常见的同步请求代码,如果我们不对 OkHttpClient 进行自定义配置的话,是直接使用以下代码的:

OkHttpClient mOkHttpClient = new OkHttpClient();

ok,就从上面入手吧:

OkHttpClient.java:

  public OkHttpClient() {
    this(new Builder());
  }
	
  OkHttpClient(Builder builder) {// 建造者设计模式
    this.dispatcher = builder.dispatcher;// 分发器,主要用于异步请求中
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);// 拦截器,OkHttp的精髓
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);// 网络拦截器,OkHttp的精髓
    this.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;// 缓存
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      X509TrustManager trustManager = systemDefaultTrustManager();
      this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;// 连接复用池
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.connectTimeout = builder.connectTimeout;// 连接超时时间,1
    this.readTimeout = builder.readTimeout;// 读取超时时间
    this.writeTimeout = builder.writeTimeout;// 写入超时时间
    this.pingInterval = builder.pingInterval;

    if (interceptors.contains(null)) {
      throw new IllegalStateException("Null interceptor: " + interceptors);
    }
    if (networkInterceptors.contains(null)) {
      throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
    }
  }

一般情况下,我们都是自定义OkHttpClient的配置:

OkHttpClient.Builder builder = new OkHttpClient.Builder();
......// 配置超时时间、拦截器等等
mOkHttpClient = builder.build();

// OkHttpClient.Builder中build()的实现如下:
public OkHttpClient build() {
  return new OkHttpClient(this);
}

可见,最后也是调用OkHttpClient(Builder builder)这个构造。

对于五层因特网协议栈中,传输层对于网络连接与网络断开,主要是依靠TCP的3次握手与4次挥手(对于这个不了解的,可见这篇文章)。为了解决TCP握手和挥手的效率问题,HTTP 有一种叫作 keepalive connections 的机制;而 OkHttp 支持 5 个并发 socket 连接,默认keepAlive时间为5分钟。OkHttp复用连接的操作,都是在ConnectionPool.java完成的(上述代码中的注解1):核心就是Deque<RealConnection>来存储连接,通过 put、get、connectionBecameIdle和evictAll几个操作来对Deque进行操作,另外通过判断连接中的计数对象StreamAllocation来进行自动回收连接(感兴趣的可看《Android进阶之光》5.6.2节内容)。

根据Request请求对象,创建一个Call对象

Call call = mOkHttpClient.newCall(request);

进入到OkHttpClient.java的newCall():

OkHttpClient.java:
  /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {// 外观设计模式
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

很明显,用到了外观设计模式。继续追踪newRealCall():

RealCall.java:

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

  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
	// 创建一个默认的重试和重定向拦截器
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

对Call对象,执行同步请求execute()

RealCall.java:

  @Override public Response execute() throws IOException {
    synchronized (this) {
	  // 如果此Call已经被执行过了,抛异常
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();// 2
    eventListener.callStart(this);// 调用callStart()表示事件开始执行
    try {
      client.dispatcher().executed(this);// 3
      Response result = getResponseWithInterceptorChain();// 4
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);// 调用callFailed()表示事件失败
      throw e;
    } finally {
      client.dispatcher().finished(this);// 5
    }
  }

OkHttpClient.java:
	
  final Dispatcher dispatcher;
  // 注解3 调用此处
  public Dispatcher dispatcher() {
    return dispatcher;
  }

注解2处就是向retryAndFollowUpInterceptor加入一个用于追踪堆栈信息的callStackTrace:

RealCall.java:

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

注解3最终的请求是dispatcher来完成的,接下来就开始分析Dispatcher:

Dispatcher.java:

/**
 * 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; // 每次调度程序空闲时调用的回调(当运行的Call返回零时)。 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<>(); // 传入一个线程池的实现 public Dispatcher(ExecutorService executorService) { this.executorService = executorService; } public Dispatcher() { } // 如果没有设置线程池,就默认创建一个 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; } ...... }

其中client.dispatcher().executed(this)在Dispatcher的实现为:

Dispatcher.java:

  /** Used by {@code Call#execute} to signal it is in-flight. */
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

无非就是加入正在运行的异步队列中。

注解4返回了一个Response对象,并且不为null时,就把这个对象返回给调用者,所以我们可以得知,网络请求的操作一定在这里执行:

RealCall.java:

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
	// 创建存放拦截器的list
    List interceptors = new ArrayList<>();
	// 首先加入的是用户自定义的拦截器,比如修改请求头的拦截器等
    interceptors.addAll(client.interceptors());
	// 加入重试与重定向拦截器
    interceptors.add(retryAndFollowUpInterceptor);
	// 加入桥接拦截器。简单说,它的作用就是将用户友好的请求转化为向服务器的请求,之后又把服务器的响应转化为对用户友好的响应
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
	// 加入缓存拦截器,若存在缓存并且可用就直接返回该缓存,否则会向服务器请求;
    interceptors.add(new CacheInterceptor(client.internalCache()));
    // 加入连接拦截器
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
	  // 如果不是针对WebSocket的网络访问,加入用户自定义的网络拦截器
      interceptors.addAll(client.networkInterceptors());
    }
	// 最后加入的是真正向服务器发出请求且得到响应的拦截器
    interceptors.add(new CallServerInterceptor(forWebSocket));
	
	// 创建拦截器链,注意此处的index的值为0,下文会提及
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
	// 链式调用拦截器,最后的返回结果就是 Response 对象
    return chain.proceed(originalRequest);
  }

getResponseWithInterceptorChain()最后是调用了RealInterceptorChain的proceed()方法返回Response对象,查看proceed()源码:

RealInterceptorChain.java:

  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
	// 如果此index下标超过了过滤器的个数,则抛出异常
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
	// index+1,得到下一个RealInterceptorChain
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
	// 获取此下标对应的Interceptor
    Interceptor interceptor = interceptors.get(index);
	// 拦截处理,传入下一个RealInterceptorChain
    Response response = interceptor.intercept(next);
	// 各种异常处理
    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }

Interceptor是一个接口,发现它有5个实现类:

我们挑一个最简单的实现类ConnectInterceptor进行分析:

ConnectInterceptor.java:

/** Opens a connection to the target server and proceeds to the next interceptor. */
public final class ConnectInterceptor implements Interceptor {
  public final OkHttpClient client;

  public ConnectInterceptor(OkHttpClient client) {
    this.client = client;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    ......// 省略无关代码
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }
}

拿到传入的RealInterceptorChain后,进行相应的处理后,继续调用proceed方法,那么接着刚才的逻辑,index+1,获取下一个interceptor,重复操作,所以现在就很清楚了,这里利用递归循环,也就是okHttp最经典的责任链模式

众所周知,递归循环一定要有结束循环的条件,那我们猜想,在拦截器链中的最后一个拦截器CallServerInterceptor,一定会结束递归:

CallServerInterceptor.java:

/** This is the last interceptor in the chain. It makes a network call to the server. */
public final class CallServerInterceptor implements Interceptor {
  private final boolean forWebSocket;

  public CallServerInterceptor(boolean forWebSocket) {
    this.forWebSocket = forWebSocket;
  }

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

    long sentRequestMillis = System.currentTimeMillis();

    ......

    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    ......

    return response;
  }

  static final class CountingSink extends ForwardingSink {
    long successfulCount;

    CountingSink(Sink delegate) {
      super(delegate);
    }

    @Override public void write(Buffer source, long byteCount) throws IOException {
      super.write(source, byteCount);
      successfulCount += byteCount;
    }
  }
}

果然在intercept()中,结束了递归。下面来张图,加深对拦截器的理解(图片取自OkHttp源码分析):

回到RealCall.execute(),无论是否出现异常,一定会执行注解5finall{}中的语句:

Dispatcher.java:

  /** Used by {@code Call#execute} to signal completion. */
  void finished(RealCall call) {
    finished(runningSyncCalls, call, false);
  }

  private  void finished(Deque calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
	  // 从Calls队列(即当前运行的同步队列runningSyncCalls)中移除该 call
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
	  // false,不执行
      if (promoteCalls) promoteCalls();
	  // 记录当前运行Call的总数量(同步+异步)
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }
	// 当运行的Call返回零,并且idleCallback不为null,执行它的run方法,进行
    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();// 这个线程具体是做什么的,我目前还没搞清楚,知道的麻烦提示下??
    }
  }

  public synchronized int runningCallsCount() {
    return runningAsyncCalls.size() + runningSyncCalls.size();
  }

同步的总结

其实分析下来,OkHttp主要是利用了分层的设计思想,采用责任链设计模式,每个拦截器Interceptor将传入的Request进行修饰,在CallServerInterceptor进行真正的网络请求,得到原始的Response,再反序返回上一级拦截器,直至返回给最终的调用者

异步请求源码分析

Request request = new Request.Builder().url("http://publicobject.com/helloworld.txt").method("GET", null).build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "请求失败", Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        String str = response.body().string();
        Log.i(TAG, "testAsyncGet() --> onResponse()" + str);
//                Log.i(TAG, "testAsyncGet() --> onResponse()"+response);//与response.body().string()不一致
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();
            }
        });
    }
});

创建OkHttpClient、根据Request请求对象,创建一个Call对象 这两个步骤是跟同步请求一样的,所以不再分析。

对Call对象,执行异步请求enqueue()

RealCall.java:

  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
	  // 如果此Call已经被执行过了,抛异常
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
	// 注解2中已说明,不再赘述
    captureCallStackTrace();
	// 调用callStart()表示事件开始执行
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));// 6
  }

注解6:

Dispatcher.java:
  synchronized void enqueue(AsyncCall call) {
	// 当前正在运行的异步数小于 64 ,并且正在运行的请求主机数小于5
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
	  // 把当前的call加入到正在运行的异步队列中
      runningAsyncCalls.add(call);
	  // 该call加入到线程池中执行
      executorService().execute(call);
    } else {
	  // 加入到异步等待队列中
      readyAsyncCalls.add(call);
    }
  }

  /** Returns the number of running calls that share a host with {@code call}. */
  private int runningCallsForHost(AsyncCall call) {
    int result = 0;
    for (AsyncCall c : runningAsyncCalls) {
      if (c.get().forWebSocket) continue;
      if (c.host().equals(call.host())) result++;
    }
    return result;
  }

既然放到了线程池中执行,当然要看看AsyncCall是Runnable还是Callable咯:

 NamedRunnable.java:
 
 /**
 * Runnable implementation which always sets its thread name.
 */
public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

  RealCall.java:
  
  final class AsyncCall extends NamedRunnable {
    ......

    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
		// 很熟悉吧?注解4中已讲解过,网络请求的操作在这里执行
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {// 如果call执行了cancel(),返回true
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));// 此处就是调用我们自定义的回调CallBack
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);// 此处就是调用我们自定义的回调CallBack
        }
      } 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);// 此处就是调用我们自定义的回调CallBack
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

Dispatch.java:

/** Used by {@code AsyncCall#run} to signal completion. */
  void finished(AsyncCall call) {
	// 注解5已讲解过,不同的是finished(Deque calls, T call, boolean promoteCalls)中的形参promoteCalls为true
    finished(runningAsyncCalls, call, true);
  }

AsyncCall其实是一个Runnable,并且在run()中主要是执行execute()。其实大部分的逻辑是跟同步的方式差不多的,执行dispatcher().finished(this)时,由于promoteCalls为true,会调用promoteCalls():

Dispatcher.java:

  private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

最关键的一点就是将异步等待队列 readyAsyncCalls 中的 call 移动到 runningAsyncCalls 中,并加入到线程池中执行。

总结

(原图来自okhttp源码分析(一)——基本流程(超详细))

你可能感兴趣的:(Android)