1. 程式人生 > >OkHttp原始碼解析(一)

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構建者模式建立的,不過有一點需要注意: 在這裡插描述 它預設的請求方法是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新增到執行佇列中,並且放到執行緒池中執行。

下一節就會去講解這個攔截器鏈,感謝!