okhttp核心原理分析(1)

更多文章分類java

文章思惟導圖

前言

進行 okhttp 的核心源碼分析,必需要搞清楚 http 協議以及相關的網絡協議。這裏只對協議容易混淆的地方進行說明。緩存

首先咱們要明確一點,要想讓兩臺計算機進行通訊,首先須要創建鏈接,也就是咱們常說的三次握手。服務器

計算機A 要想和計算機 B 進行通訊,首先要知道計算機B 的IP 地址,知道 IP 地址後,就能訪問計算機B,而要和計算機B上的那個程序通訊,這個時候就須要 TCP 的地址了,也就是端口號。有了這兩個信息,二者就能夠創建鏈接了。其實這個時候就能夠進行通訊了。體如今代碼中,就是經過 Socket 創建鏈接,而後進行讀寫操做。markdown

這個時候也看出來了,所謂的 Socket 其實就是對 TCP/IP 創建鏈接通訊的一種具體封裝,不一樣的語言代碼有不一樣的實現。有了 Socket 後,開發者就能夠方便地進行網絡鏈接通訊了。Socket 自己並非 TCP/IP網絡協議中的協議網絡

HTTP 協議就是在創建了 Socket 鏈接後規定了通訊內容的格式,你們都聽從這個協議進行通訊。異步

HTTP通訊內容?ide

簡單來講,所謂的 HTTP 通訊就是創建 Socket 鏈接,而後把通訊內容拼接成符合 HTTP 報文的內容發送出去。oop

什麼是 okhttp

有了前言的內容,咱們就能夠理解什麼是 okhttp 了,所謂的 okhttp 就是經過代碼的方式實現了各類協議,將這些通訊協議封裝起來,讓咱們能夠快速地用代碼來實現。源碼分析

okhttp 好處

  • 支持 HTTP一、HTTP二、Quic以及 WebSocketui

    之因此支持,是由於 okhttp 的源碼裏面對這些協議的規則進行了實現。

  • 鏈接池複用底層 TCP鏈接,減小請求延時。

    創建 TCP 鏈接是須要時間的,okHTTP 源碼中對已經鏈接的 TCP,其實在代碼中的體現就是 Socket 進行了緩存,再次請求同一地址的時候就不用重複創建鏈接了,從而減小請求延時。

  • 無縫的支持 GZIP 減小數據流量

    其實這是 HTTP 協議的內容,HTTP 協議中能夠在請求頭中規定是否支持數據壓縮,okhttp 就把這個請求頭封裝進去了,告訴服務器,我能夠接受一個 GZIP 壓縮的數據報文。

  • 緩存響應數據減小重複的網絡請求

    這也是 HTTP 協議中定義的內容,有對應的字段表示

  • 請求失敗自動重試主機的其餘 ip,自動重定向

    一樣也是 HTTP 協議中定義的內容。

可見所謂的這些好處,其實就是 okhttp 利用 HTTP 報文格式中規定的內容,而後進行處理,完成這些規定。若是沒有處理的話,任憑服務器發送來的報文是什麼,若是通通無論的話,那也是沒用的。

所以再次說明 HTTP 協議只是規定了你我通訊要發送的內容須要聽從什麼樣的格式,至於我有沒有根據內容,實現對應的功能,那就不是 HTTP 協議的範圍了。

okhttp 使用

// 步驟 1 
	OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .readTimeout(60,TimeUnit.SECONDS)
                .connectTimeout(60,TimeUnit.SECONDS)
                .cache(new Cache(new File("xx"),1024))
                .build();
	// 步驟 2
        Request request = new Request.Builder()
                .url(AppConfig.URL.url_get)
                .build();
    // 步驟 3 
        Call call = okHttpClient.newCall(request);
   // 步驟 4 
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });
複製代碼

okhttp 的使用通常就是上面 4 步。

第一步:建立 okhttpClient ,也就是一個客戶端,同時也是也 Call 的工廠,主要做用就是記錄一些配置內容,好比 : 鏈接超時時間、讀取超時時間、緩存地址等等這種配置。這個對象能夠共用,不用每次都建立。

第二步:就是建立一個請求報文。

第三步:就是經過 Call 工廠 okhttpClient 和 請求報文,構建出一個準備好要執行的請求。經過 Call 來發起網絡請求。

第四步:發起網絡請求

雖然就這樣簡單的四步,可是代碼設計的很是好,首先作到了功能分離!單一職責,有三個類 OkhttpClientRequestCall 分別負責不一樣的職責,很是清晰。

核心原理分析

okhttp 整個大的流程核心就是一個分發器 Dispatcher 和 攔截器 interceptors 下面分別分析

Dispatcher

分發器用於執行咱們網絡請求的異步任務,Dispatcher 有 4 個核心成員對象 :

  • ExecutorService

    線程池,用於執行異步任務

  • 三個隊列 Deque<AsynCall>

    三個隊列,分別是用於存儲 正在執行的異步任務、正在執行的同步任務、準備執行的異步任務

先看一張流程圖

Dispatcher 的整個執行流程就如上圖所示,下面來結合源碼分別介紹。

// 異步請求
call.enqueue(new Callback() );
// 這個時候會執行 RealCall 下面的方法
複製代碼

這個時候就進入 Dispatcher 分發器

重點來了

首先這個方法是個同步方法,有個判斷,判斷這個請求是放入 running 隊列仍是 ready 隊列。

圖中的1 就是判斷條件,若是 running 隊列中的 call 小於最大請求數(默認 64)而且對同一地址的請求小於 最大主機請求數(默認5),這個時候就放入 running 隊列,直接交給線程池來執行 請求。不然加入 ready 隊列,等待請求。

而後看 executorService().execute(call) 這一步其實就是交給線程池執行,最終執行的是 AsyncCallexecute() 方法

注意這個方法是在子線程中執行的。

1: 是真正的觸發網絡請求,進入下一個核心點 「攔截器」。(後面講解)

2:能夠看到 2 是在 finally 中執行的,也就是老是會執行到。

1:執行完畢後就把 call 從 runing 隊列中移除了,而後執行 2

這裏會根據條件循環判斷 ready隊列中的 call 是否能添加到 running 隊列中執行。

到此整個分發器的執行流程就結束了!

總結

對於 Dispatcher 分發器核心點就是一個線程池、維持請求隊列。

添加一個請求的時候會判斷正在請求的數量,若是條件知足就放入線程池執行,不然放入等待隊列,等待執行。

後面咱們會繼續介紹下一個核心-----攔截器

相關文章
相關標籤/搜索