面試系列“講一下吧”之 OkHttp 源碼解析

閱讀指南:
本博客,前面源碼部分,duck不必細看,大概瞄一眼就行,或只看我加註釋的部分就行。我會在文末描述下大概流程把流程理清楚了再看代碼比較好,看代碼注意只看主要流程,其他分支末節,有時間自己慢慢研究就行。

使用

沒什麼好說的,記住這麼用就好。

val okHttpClient = OkHttpClient()
val request = Request.Builder()
    .url("https://xxxx")
    .build()
val call = okHttpClient.newCall(request)
call.enqueue(object :okhttp3.Callback{
    override fun onFailure(call: okhttp3.Call, e: IOException) {
        
    }

    override fun onResponse(call: okhttp3.Call, response: okhttp3.Response){
        
    }
})

OkHttpClient

OkHttpClient 構造方法的各種參數,瞭解一下就好,也可以直接跳過。

//建造者模式
public OkHttpClient() {
  this(new Builder());
}

//就是一些初始化的參數大概看一看就好
public static final class Builder {
  //用於調度線程的
  Dispatcher dispatcher;
  //網絡代理
  @Nullable Proxy proxy;
  //支持的協議的版本
  List<Protocol> protocols;
  //支持http、https的配置,https的各種加密協議
  List<ConnectionSpec> connectionSpecs;
  //攔截器
  this.interceptors.addAll(okHttpClient.interceptors);
  this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
  //做統計相關的
  EventListener.Factory eventListenerFactor
  ProxySelector proxySelector;
  //餅乾罐子,存儲cookie用的
  CookieJar cookieJar;
  //httpCache
  @Nullable Cache cache;
  @Nullable InternalCache internalCache;
  //獲取連接端口,socket是TCP的東西
  SocketFactory socketFactory;
  //SSL連接的Factory
  @Nullable SSLSocketFactory sslSocketFactory;
  //服務器證書
  @Nullable CertificateChainCleaner certificateChainCleaner;
  //主機名驗證器,for https。
  HostnameVerifier hostnameVerifier;
  //自簽名證書的驗證,利用公鑰來驗證的。
  CertificatePinner certificatePinner;
  //授權用的(代理用的)
  Authenticator proxyAuthenticator;
  //正常用的授權
  Authenticator authenticator;
  //連接池,待緩存的集合
  ConnectionPool connectionPool;
  Dns dns;
  //重定向時候有一個https,可能是跳過去,可能是跳過來
  boolean followSslRedirects;
  //重定向跳轉
  boolean followRedirects;
  //連接失敗了是否要重新連接
  boolean retryOnConnectionFailure;
  int callTimeout;
  //TCP連接時間
  int connectTimeout;
  int readTimeout;
  int writeTimeout;
  //針對websocket的
  int pingInterval;
}

execute

call.execute() 

這是同步的執行方法。

@Override public Response execute() throws IOException {
//如果執行過,就報錯
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  //transmitter 發射臺的意思,先忽略下面兩句
  transmitter.timeoutEnter();
  transmitter.callStart();
  try {
    //重點:dispatcher執行這個Call,對應下面的加入runningSyncCalls
    client.dispatcher().executed(this);
    //這行直接跳轉下面標題
    return getResponseWithInterceptorChain();
  } finally {
    client.dispatcher().finished(this);
  }
}


/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
//加入正在執行的雙端隊列
  runningSyncCalls.add(call);
}

enqueue

//異步方法
@Override public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  transmitter.callStart();
  //看這行
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

//responseCallback封裝一個AsyncCall,並加入 readyAsyncCalls
void enqueue(AsyncCall call) {
  synchronized (this) {
    readyAsyncCalls.add(call);
    // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
    // the same host.
    if (!call.get().forWebSocket) {
      AsyncCall existingCall = findExistingCallWithHost(call.host());
      if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
    }
  }
  promoteAndExecute();
}

接下來,我們從AsyncCall中找繼續執行的方法,發現這個 AsyncCall 繼承了一個 NamedRunnable implements Runnable,然後我們閱讀 run() 方法。

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

//找到 run 方法了
  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
    //發現裏面調用了execute,是一個抽象類的抽象方法,去子類 AsyncCall 中找 execute 方法
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}


//找到啦!
@Override protected void execute() {
  boolean signalledCallback = false;
  transmitter.timeoutEnter();
  try {
    //發現,還是走到了一個關鍵的方法,這個在下面有解析
    Response response = getResponseWithInterceptorChain();
    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 {
      responseCallback.onFailure(RealCall.this, e);
    }
  } catch (Throwable t) {
    cancel();
    if (!signalledCallback) {
      IOException canceledException = new IOException("canceled due to " + t);
      canceledException.addSuppressed(t);
      responseCallback.onFailure(RealCall.this, canceledException);
    }
    throw t;
  } finally {
    client.dispatcher().finished(this);
  }
}

dispatcher

這個裏面有三個雙向隊列。一個是爲同步使用的,另外兩個是爲異步使用的。
這個類裏面初始化了線程池,用線程池來處理線程,提高了程序的性能,爲異步操作提供的。

/** 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<>();

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


//線程池的初始化方法
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;
}

//promoteAndExecute 方法是線程池的 start 方法
/**
 * Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs
 * them on the executor service. Must not be called with synchronization because executing calls
 * can call into user code.
 *
 * @return true if the dispatcher is currently running calls.
 */
private boolean promoteAndExecute() {
  assert (!Thread.holdsLock(this));
  List<AsyncCall> executableCalls = new ArrayList<>();
  boolean isRunning;
  synchronized (this) {
  //對 readyAsyncCalls 進行遍歷
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall asyncCall = i.next();
      //兩個判斷,一個事判斷最大請求數>=64,一個是每個主機的請求數 >= 5
      if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
      if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
      i.remove();
      asyncCall.callsPerHost().incrementAndGet();
      executableCalls.add(asyncCall);
      //添加到 runningAsyncCalls
      runningAsyncCalls.add(asyncCall);
    }
    isRunning = runningCallsCount() > 0;
  }
  for (int i = 0, size = executableCalls.size(); i < size; i++) {
    AsyncCall asyncCall = executableCalls.get(i);
    //執行這個 AsyncCall
    asyncCall.executeOn(executorService());
  }
  return isRunning;
}

getResponseWithInterceptorChain(重點啊)

責任鏈模式

Response getResponseWithInterceptorChain() throws IOException {
  // Build a full stack of interceptors.
  List<Interceptor> interceptors = new ArrayList<>();
  //添加一大堆的攔截器
  interceptors.addAll(client.interceptors());
  interceptors.add(new RetryAndFollowUpInterceptor(client));
  interceptors.add(new BridgeInterceptor(client.cookieJar()));
  interceptors.add(new CacheInterceptor(client.internalCache()));
  interceptors.add(new ConnectInterceptor(client));
  if (!forWebSocket) {
    interceptors.addAll(client.networkInterceptors());
  }
  interceptors.add(new CallServerInterceptor(forWebSocket));

//這個chain把所有的攔截器都裝了進去
  Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
      originalRequest, this, client.connectTimeoutMillis(),
      client.readTimeoutMillis(), client.writeTimeoutMillis());

  boolean calledNoMoreExchanges = false;
  try {
  //然後開始調用 chain 的 Proceed 方法
    Response response = chain.proceed(originalRequest);
    if (transmitter.isCanceled()) {
      closeQuietly(response);
      throw new IOException("Canceled");
    }
    return response;
  } catch (IOException e) {
    calledNoMoreExchanges = true;
    throw transmitter.noMoreExchanges(e);
  } finally {
    if (!calledNoMoreExchanges) {
      transmitter.noMoreExchanges(null);
    }
  }
}

//chain只有一個實現類就是RealInterceptorChain,所以我們來到這個類的 proceed 方法

@Override public Response proceed(Request request) throws IOException {
  return proceed(request, transmitter, exchange);
}

public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
    throws IOException {
//判斷錯誤,不用看
  if (index >= interceptors.size()) throw new AssertionError();

  calls++;

  // If we already have a stream, confirm that the incoming request will use it.
  if (this.exchange != null && !this.exchange.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.exchange != 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 從0開始,在上面調用的代碼中有描述
  RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
      index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
  Interceptor interceptor = interceptors.get(index);
  //開始調用各個攔截器的 intercept 方法,所有的攔截器都 implements 了 Interceptor,跳轉到分析 RetryAndFollowUpInterceptor(默認這是第一個) 
  Response response = interceptor.intercept(next);

  // Confirm that the next interceptor made its required call to chain.proceed().
  if (exchange != 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;
}

RetryAndFollowUpInterceptor implements Interceptor

Interceptor 這個接口類中只有一個方法

Response intercept(Chain chain) throws IOException;

其次還有一個 Chain 類,其中有一個關鍵方法,叫 proceed

Response proceed(Request request) throws IOException;

我們從 RetryAndFollowUpInterceptor 開始看,我們先分析這個責任鏈模式。
我們可以把 RetryAndFollowUpInterceptor 這個類的 intercept 簡化爲下面代碼

@Override public Response intercept(Chain chain) throws IOException {
    //做一些其他的準備工作
    response = realChain.proceed(request, transmitter, null);
    //處理response
    return response;
}

當調用的 proceed 方法的時候,我們就會調用到 realChain.proceed 方法,這樣 index + 1,就會執行到下一個 Interceptor 的 intercept 方法,也就是 BridgeInterceptor 的 intercept 方法。我畫一個圖示意。

image

BridgeInterceptor implements Interceptor

CacheInterceptor implements Interceptor

ConnectInterceptor implements Interceptor

建立TCP連接。

OkHttp的主要用途是封裝了網絡請求,讓我們更簡單的操作網絡請求。

  1. 使用線程池提高了性能。
  2. 然後就是攔截器部分,使用了責任鏈模式。熟悉下每個攔截器的作用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章