国庆期间,没怎么出去玩,就宅在家里面学习,所以就来研究了一下okhttp的源码。okhttp的github地址https://github.com/square/okhttp

简单使用

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
        .url("www.baidu.com")
        .build();
Call call = okHttpClient.newCall(request);

//同步请求
try {
    Response response = call.execute();
} catch (IOException e) {
    e.printStackTrace();
}

//异步请求
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {}
    @Override
    public void onResponse(Call call, Response response) throws IOException {}
});

它的用法也是比较简单,前三步中异步跟同步的操作基本是一样的,就是最后稍有不同,好,我们现在就来逐一进行解析。

源码解析

  • OkHttpClient

首先我们来看看OkHttpClient实例的创建
OkHttpClient okHttpClient = new OkHttpClient.Builder().build()
它首先是通过一个构建者模式来创建它的一个实例。

public Builder() {
  dispatcher = new Dispatcher();
  protocols = DEFAULT_PROTOCOLS;
  connectionSpecs = DEFAULT_CONNECTION_SPECS;
  eventListenerFactory = EventListener.factory(EventListener.NONE);
  proxySelector = ProxySelector.getDefault();
  cookieJar = CookieJar.NO_COOKIES;
  socketFactory = SocketFactory.getDefault();
  hostnameVerifier = OkHostnameVerifier.INSTANCE;
  certificatePinner = CertificatePinner.DEFAULT;
  proxyAuthenticator = Authenticator.NONE;
  authenticator = Authenticator.NONE;
  connectionPool = new ConnectionPool();
  dns = Dns.SYSTEM;
  followSslRedirects = true;
  followRedirects = true;
  retryOnConnectionFailure = true;
  connectTimeout = 10_000;
  readTimeout = 10_000;
  writeTimeout = 10_000;
  pingInterval = 0;
}

而Builder类是OkHttpClient的一个内部类,通过调用它的build方法就会把OkHttpClient的实例创建出来

public OkHttpClient build() {
  return new OkHttpClient(this);
}
  • Request

把OkHttpClient实例创建出来之后,接着就是Request的创建。其实它的创建跟OkHttpClient的创建大同小异,也是通过builder构建者模式创建的,不过有一点需要注意:
OkHttp源码解析(一)-LMLPHP
它默认的请求方法是get。

  • Call
Call call = okHttpClient.newCall(request);

这个Call其实只是一个接口,因此不能直接创建它的实例,只能是去创建它的子类。

public interface Call extends Cloneable {
  /** Returns the original request that initiated this call. */
  Request request();

  Response execute() throws IOException;

  void enqueue(Callback responseCallback);

  void cancel();

  boolean isExecuted();

  boolean isCanceled();

  Call clone();

  interface Factory {
    Call newCall(Request request);
  }
}

这里它是利用我们刚刚创建好的okHttpClient实例的newCall方法进行创建,好我们就走进去看看:

@Override public Call newCall(Request request) {
  return RealCall.newRealCall(this, request, false /* for web socket */);
}

我们发现它这里是通过RealCall的newRealCall方法去创建的,我们继续往里面看:

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的实例,而这个RealCall也是实现了Call接口的,我们看看这个RealCall的构造方法:

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

这里传递了OkHttpClient、Request的实例,还有就是创建了RetryAndFollowUpInterceptor这个拦截器类,拦截器在后面会有讲解,这是非常重要的一点。

因为同步和异步的前三步都是一样的,那我们现在来看看最后一步大家有什么区别。

1. 同步

同步的话就会去调用Call的execute方法,从上面的讲解也知道Call是一个接口,所以调用的是它的实现类RealCall。

@Override public Response execute() throws IOException {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  eventListener.callStart(this);
  try {
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
  } catch (IOException e) {
    eventListener.callFailed(this, e);
    throw e;
  } finally {
    client.dispatcher().finished(this);
  }
}

这里首先就会去判断executed这个标志位是否为true,因为同一个请求只能是请求一次。
接下去往下看这句client.dispatcher().executed(this)。
这里会调用client.dispatcher的exceuted方法。而client的dispatcher方法获取的就是Dispatcher这个实例,这个类的实例是在构建OkHttpClient的时候创建的。Dispatcher这个类是很重要的一个类,它维护请求的状态(同步还是异步),并且维护一个线程池,用于执行请求,这从后面可以知道。那我们现在看看它的executed方法:

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

这里出现了一个runningSyncCalls这个变量,究竟是什么呢?我们看看它的定义,也是在Dispatcher这个类里面:

/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

其实它就是一个队列,当有同步请求的时候,就会把这个Call添加到一个同步队列中去。

回到RealCall的executed方法中去,把RealCall添加到同步队列之后,就会去调用getResponseWithInterceptorChain()这个方法获取Response,这个方法可以说是整个OkHttp最重要的部分,拦截器链,这里我们留到下一章节来说。现在我们来看看finally那部分:

client.dispatcher().finished(this);

这里会调用Dispatcher的finish方法,里面做了什么,我们进去看看:

void finished(RealCall call) {
  finished(runningSyncCalls, call, false);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
  int runningCallsCount;
  Runnable idleCallback;
  synchronized (this) {
    if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
    if (promoteCalls) promoteCalls();
    runningCallsCount = runningCallsCount();
    idleCallback = this.idleCallback;
  }
  if (runningCallsCount == 0 && idleCallback != null) {
    idleCallback.run();
  }
}

它这里会把同步队列runningSyncCalls和当前的Call作为参数传到finished的重载方法中。在这个重载方法里面可以看到,它会把这个同步的Call从队列中移除。因为传进来的promoteCalls是为false,所以promoteCalls这个方法就不会执行,接下来就会调用runningCallsCount()这个方法,从名字上我们可以猜测它应该是统计Call的数量:

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

它是在统计两个队列的数量,runningAsyncCalls是接下来会讲解到运行中的异步队列。这样同步的讲解完了,接下来就要看看异步的了。

2. 异步

异步调用的是Call的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));
}

同样的,我们只需要看最后一行,它首先new了一个AsyncCall实例,我们看看它的定义

final class AsyncCall extends NamedRunnable

它是RealCall里面的一个内部类,而它又继承了一个NamedRunnable,我们又继续看看这个NameRunnable:

public abstract class NamedRunnable implements Runnable

现在终于明白了,原来这个AsyncCall就是一个Runnable线程。好我们看回Dispatcher的enqueue的这个方法

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

这里有几个变量,我们先来看看它的定义:

private int maxRequests = 64;
private int maxRequestsPerHost = 5;

/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

这几个都是Dispatcher的成员变量
maxRequests:最大可执行的线程数
maxRequestsPerHost:最大的主机数
readyAsyncCalls:异步的就绪队列
runningAsyncCalls:异步的执行队列

回到enqueue方法,若条件不符合的时候,就会把Call添加到异步的就绪队列中等待;若条件成立的话就会把Call添加到执行队列,然后调用executorService().execute(call)。这里出现了一个executorService()方法,我们看看:

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

这里会返回一个线程池,在Dispatcher类中也是维护了一个自己的线程池来执行AsyncCall。那我们来看看AsyncCall的run方法,但是AsyncCall里面并没有run方法,而它的run方法是在它的父类NamedRunnable中,而最终也是会调用execute方法,所以我们看看AsyncCall的execute方法:

@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,后面会讲到,然后就处理回调消息。同样的我们也要看看finally里面的finished方法。

/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
  finished(runningAsyncCalls, call, true);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
  int runningCallsCount;
  Runnable idleCallback;
  synchronized (this) {
    if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!
    if (promoteCalls) promoteCalls();
    runningCallsCount = runningCallsCount();
    idleCallback = this.idleCallback;
  }
  if (runningCallsCount == 0 && idleCallback != null) {
    idleCallback.run();
  }
}

这里跟同步里面的finished方法差不多,其中的一个区别就是promoteCalls是为true的,所以就会去调用promoteCalls()这个方法,那我们进去看看:

private void promoteCalls() {
  if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
  if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
  for (Iterator<AsyncCall> 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.
  }
}

这里首先会判断正在运行的异步队列数量有没有超过最大限值,然后就是遍历这个异步的就绪队列,把就绪队列中的AsyncCall添加到执行队列中,并且放到线程池中执行。

下一节就会去讲解这个拦截器链,感谢!

10-06 14:42