Android OkHttp3原始碼詳解——整體框架

張啟露發表於2018-05-02

一 前言

之前寫過一遍文章Android OkHttp3簡介和使用詳解,當時說要寫 OkHttp3原始碼詳解,由於各種原因,原始碼詳解來的有點晚,下面我們先來來看一下流程圖。

這裡寫圖片描述

二 原始碼整體架構

這裡寫圖片描述
上圖是OkHttp3的整體框架,大致可以分為以下幾層:

  • Interface——介面層:接收使用者的網路訪問請求(同步請求/非同步請求),發起實際的網路訪問
  • Protocol——協議層:處理協議邏輯
  • Connection——連線層:管理網路連線,傳送新的請求,接收伺服器訪問
  • Cache——快取層:管理本地快取
  • I/O——I/O層:實際資料讀寫實現
  • Inteceptor——攔截器層:攔截網路訪問,插入攔截邏輯

2.1 Interface——介面層

介面層接收使用者的網路訪問請求(同步請求/非同步請求),發起實際的網路訪問

  1. OkHttpClient:是OkHttp框架的客戶端,更確切的說是一個使用者皮膚。使用者使用OkHttp進行各種設定,發起各種網路請求都是通過OkHttpClient完成的。每個OkHttpClient內部都維護了屬於自己的任務佇列,連線池,Cache,攔截器等,所以在使用OkHttp作為網路框架時應該全域性共享一個OkHttpClient例項。

  2. Call:Call是描述一個實際的訪問請求,使用者的每一個網路請求都是一個Call例項。Call本身只是一個介面,定義了Call的介面方法,實際執行過程中,OkHttp會為每一個請求建立一個RealCall,每一個RealCall內部有一個AsyncCall,AsyncCall是RealCall的一個內部類並且繼承NamedRunnable,那麼首先看NamedRunnable類是什麼樣的,如下:

public abstract class NamedRunnable implements Runnable {
  ......

  @Override 
  public final void run() {
   ......
    try {
      execute();
    }
    ......
  }

  protected abstract void execute();
}

NamedRunnable實現了Runnable介面並且是一個抽象類,有一個抽象方法execute(),這個方法在run()中被呼叫。這也就意味著NamedRunnable是一個執行緒,並且其子類應該實現execute方法。下面再看AsyncCall的實現:

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

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

    ......
final class RealCall implements Call {
  @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) {
  ......
  responseCallback.onFailure(RealCall.this, e);

} finally {
    client.dispatcher().finished(this);
  }
}

AsyncCall繼承NamedRunnable,實現了抽象方法execute(),所以每一個Call就是一個執行緒,而執行Call的過程就是執行其execute()方法的過程。

3.Dispatcher(排程器)是OkHttp的任務佇列,其內部維護了一個執行緒池,當有接收到一個Call時,Dispatcher負責線上程池中找到空閒的執行緒並執行其execute方法。

2.2 Protocol——協議層

Protocol層負責處理協議邏輯,OkHttp支援Http1/Http2/WebSocket協議,並在3.7版本中放棄了對Spdy協議,鼓勵開發者使用Http/2。
在早期的版本中,OkHttp支援Http1.0,1.1,SPDY協議,但是Http2協議的問世,導致OkHttp也做出了改變,OkHttp鼓勵開發者使用HTTP2,不再對SPDY協議給予支援。另外,新版本的OkHttp還有一個新的亮點就是支援WebScoket,這樣我們就可以非常方便的建立長連線了。在安全方便,OkHttp目前支援了TLS版本,以確保一個安全的Socket連線。

2.3 Connection——連線層:管理網路連線,傳送新的請求,接收伺服器訪問

連線層顧名思義就是負責網路連線。在連線層中有一個連線池,統一管理所有的Socket連線,當使用者新發起一個網路請求時,OkHttp會首先從連線池中查詢是否有符合要求的連線,如果有則直接通過該連線傳送網路請求;否則新建立一個網路連線。
雖然你只需要提供URL,但OkHttp計劃它連線到您的網路伺服器需要使用三種型別:URL,地址和路線.

  1. RealConnection:描述一個物理Socket連線,連線池中維護多個RealConnection例項。
  2. StreamAllocation: 由於Http/2支援多路複用,一個RealConnection可以支援多個網路訪問請求,所以OkHttp又引入了StreamAllocation來描述一個實際的網路請求開銷(從邏輯上一個Stream對應一個Call,但在實際網路請求過程中一個Call常常涉及到多次請求。如重定向,Authenticate等場景。所以準確地說,一個Stream對應一次請求,而一個Call對應一組有邏輯關聯的Stream),一個RealConnection對應一個或多個StreamAllocation,所以StreamAllocation可以看做是RealConenction的計數器,當RealConnection的引用計數變為0,且長時間沒有被其他請求重新佔用就將被釋放。

2.4 Cache——快取層

Cache層負責維護請求快取,當使用者的網路請求在本地已有符合要求的快取時,OkHttp會直接從快取中返回結果,從而節省網路開銷。

2.5 I/O層

I/O層負責實際的資料讀寫。OkHttp的另一大有點就是其高效的I/O操作,這歸因於其高效的I/O庫okio。

2.6 Inteceptor——攔截器層

攔截器是一種強大的機制,可以監視、重寫和重試呼叫。攔截器層提供了一個類AOP介面,方便使用者可以切入到各個層面對網路訪問進行攔截並執行相關邏輯。

相關文章