OkHttp源碼分析系列--整體的工作流程

OkHttp作為時(shí)下最受歡迎的網(wǎng)絡(luò)請(qǐng)求框架之一米同,它有著自己的優(yōu)點(diǎn):

  • 使用了眾多的設(shè)計(jì)模式(如:Builder模式、責(zé)任鏈模式等)躯保,尤其是在Interceptor中使用的責(zé)任鏈模式,將整個(gè)網(wǎng)絡(luò)請(qǐng)求串聯(lián)起來最為經(jīng)典。
  • 基于Http請(qǐng)求頭专执、DiskLruCache等緩存策略實(shí)現(xiàn)Respose的緩存。
  • 內(nèi)部維護(hù)了隊(duì)列線程池郁油,可以輕松實(shí)現(xiàn)并發(fā)任務(wù)本股。
  • 擁有自動(dòng)維護(hù)的socket連接池,減少握手次數(shù)桐腌。

除了上面的優(yōu)點(diǎn)拄显,其實(shí)還有很多,這里就不一一詳述了案站。

大家都應(yīng)該知道OkHttp執(zhí)行網(wǎng)絡(luò)請(qǐng)求有兩種方式:

  • 1躬审、同步網(wǎng)絡(luò)請(qǐng)求--Call.execute();
  • 2.異步網(wǎng)絡(luò)請(qǐng)求--Call.enqueue(Callback responseCallback)。

那么接下來就從這兩個(gè)方面進(jìn)行分析。

1.Call對(duì)象的真實(shí)面貌——RealCall

  • OkHttpClient#newCall():

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

    從上述代碼忧设,我們發(fā)現(xiàn)Call的實(shí)現(xiàn)類原來是RealCall,并且創(chuàng)建RealCall對(duì)象時(shí)博助,會(huì)需要OkHttpClient、Request以及forWebSocket誊稚。

  • RealCall詳細(xì)分析:

RealCall.png
  • RealCall構(gòu)造方法
    構(gòu)造方法中除了會(huì)保存之前的OkHttpClient翔始、Request、boolean forWebSocket之外里伯,還會(huì)創(chuàng)建RetryAndFollowUpIntercptor對(duì)象城瞎,這個(gè)對(duì)象主要作用是在網(wǎng)絡(luò)請(qǐng)求是出現(xiàn)異常情況進(jìn)行重新連接的,具體的分析放在后面疾瓮。

  • execute()同步請(qǐng)求方法:
    既然是同步網(wǎng)絡(luò)請(qǐng)求脖镀,那么就意味著不需要為它去執(zhí)行分配線程的操作了。并且它應(yīng)該會(huì)直接進(jìn)入網(wǎng)絡(luò)請(qǐng)求的操作狼电。

          @Override public Response execute() throws IOException {
                ...
                // 通過Dispatcher管理網(wǎng)絡(luò)請(qǐng)求——對(duì)于同步請(qǐng)求只是將其添加到runningSyncCalls隊(duì)列中蜒灰。
                client.dispatcher().executed(this);
                // 構(gòu)建一堆的網(wǎng)絡(luò)請(qǐng)求攔截器
                Response result = getResponseWithInterceptorChain();
                return result;
                ...
            }
    
  • getResponseWithInterceptorChain() 分析:

          Response getResponseWithInterceptorChain() throws IOException {
              // Build a full stack of interceptors.
              // 1.創(chuàng)建interceptors集合。
              List<Interceptor> interceptors = new ArrayList<>();
              // 2.添加用戶設(shè)置的所有的interceptors肩碟。
              interceptors.addAll(client.interceptors());
              // 3.添加錯(cuò)誤重連的Interceptor强窖,此對(duì)象在構(gòu)造方法中被創(chuàng)建。
              interceptors.add(retryAndFollowUpInterceptor);
              // 4.添加BridgeInterceptor攔截器削祈,將用戶設(shè)置的Request進(jìn)行高度封裝(請(qǐng)求頭翅溺、關(guān)于響應(yīng)體的解gzip)脑漫。
              interceptors.add(new BridgeInterceptor(client.cookieJar()));
              // 5.添加處理網(wǎng)絡(luò)請(qǐng)求對(duì)應(yīng)緩存的攔截器
              interceptors.add(new CacheInterceptor(client.internalCache()));
              // 6.添加進(jìn)行Socket連接的攔截器
              interceptors.add(new ConnectInterceptor(client));
              // 7.添加用戶定義的網(wǎng)絡(luò)攔截器
              if (!forWebSocket) {
                interceptors.addAll(client.networkInterceptors());
              }
              // 8.添加Socket下與服務(wù)器進(jìn)行數(shù)據(jù)讀寫操作的攔截器。
              interceptors.add(new CallServerInterceptor(forWebSocket));
          
              // 9.責(zé)任鏈模式中保存了下一攔截器的鏈條對(duì)象(遞歸執(zhí)行的關(guān)鍵)咙崎。
              Interceptor.Chain chain = new RealInterceptorChain(
                  interceptors, null, null, null, 0, originalRequest);
              return chain.proceed(originalRequest);
          }
    

    構(gòu)建一堆的Interceptor之后优幸,執(zhí)行RealInterceptorChain中的proceed()方法,開啟整個(gè)網(wǎng)絡(luò)請(qǐng)求責(zé)任鏈工作褪猛。

    RealInterceptorChain # proceed()源碼分析:

          public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
                RealConnection connection) throws IOException {
              ...
              // Call the next interceptor in the chain.
              // 1.創(chuàng)建保存了下一個(gè)interceptor的鏈條對(duì)象网杆。
              RealInterceptorChain next = new RealInterceptorChain(
                  interceptors, streamAllocation, httpCodec, connection, index + 1, request);
              // 2.執(zhí)行當(dāng)前當(dāng)前interceptor的intercept()方法。
              Interceptor interceptor = interceptors.get(index);
              Response response = interceptor.intercept(next);
              ...
              return response;
            }
    
  • 再來分析enqueue()異步網(wǎng)絡(luò)請(qǐng)求:

    既然是異步網(wǎng)絡(luò)請(qǐng)求伊滋,那么肯定需要兩個(gè)條件:
    1碳却、網(wǎng)絡(luò)請(qǐng)求的任務(wù)體;
    2新啼、執(zhí)行具體任務(wù)的工作線程追城。

          @Override 
          public void enqueue(Callback responseCallback) {
              ...
              client.dispatcher().enqueue(new AsyncCall(responseCallback));
              ...
          }
    
  • AsyncCall.execute()源碼分析:

          protected void execute() {
            ...
            // 我們發(fā)現(xiàn)其實(shí)AsyncCall最后也是做了這件事情
            Response response = getResponseWithInterceptorChain();
            ...  
          }
    

2.管理網(wǎng)絡(luò)請(qǐng)求任務(wù)的策略器——Dispatcher

Dispatcher主要的工作就是給異步網(wǎng)絡(luò)請(qǐng)求任務(wù)(AsyncCall)分配工作線程并執(zhí)行。


Dispatcher.png
  • Dispatcher.enqueue()源碼分析:

      synchronized void enqueue(AsyncCall call) {
          // 1.檢測(cè)正在執(zhí)行的異步網(wǎng)絡(luò)請(qǐng)求數(shù)是否小于maxRequests
          // &&相同主機(jī)的異步網(wǎng)絡(luò)請(qǐng)求數(shù)是否小于maxRequestsPerHost
          if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
            // 2.滿足條件燥撞,添加到runningAsyncCalls隊(duì)列并且執(zhí)行。
            runningAsyncCalls.add(call);
            executorService().execute(call);
          } else {
            // 3.不滿足條件迷帜,添加到readyAsyncCalls物舒。
            readyAsyncCalls.add(call);
          }
       }
    
  • Dispatcher.executed()源碼分析:

      synchronized void executed(RealCall call) {
          // 直接添加到runningSyncCalls隊(duì)列
          runningSyncCalls.add(call);
       }
    

關(guān)于Okhttp的整體工作流程,基本上就是這個(gè)樣子戏锹。至于Interceptor的源碼分析冠胯,會(huì)在后續(xù)的文章中給出。最后把整體流程圖貼出來:

OkHttp.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锦针,一起剝皮案震驚了整個(gè)濱河市荠察,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奈搜,老刑警劉巖悉盆,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異馋吗,居然都是意外死亡焕盟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門宏粤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脚翘,“玉大人,你說我怎么就攤上這事绍哎±磁” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵崇堰,是天一觀的道長(zhǎng)沃于。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么揽涮? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任抠藕,我火速辦了婚禮,結(jié)果婚禮上蒋困,老公的妹妹穿的比我還像新娘盾似。我一直安慰自己,他們只是感情好雪标,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布零院。 她就那樣靜靜地躺著,像睡著了一般村刨。 火紅的嫁衣襯著肌膚如雪告抄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天嵌牺,我揣著相機(jī)與錄音打洼,去河邊找鬼。 笑死逆粹,一個(gè)胖子當(dāng)著我的面吹牛募疮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播僻弹,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼阿浓,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了蹋绽?” 一聲冷哼從身側(cè)響起芭毙,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卸耘,沒想到半個(gè)月后退敦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹊奖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年苛聘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忠聚。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡设哗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出两蟀,到底是詐尸還是另有隱情网梢,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布赂毯,位于F島的核電站战虏,受9級(jí)特大地震影響拣宰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜烦感,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一巡社、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧手趣,春花似錦晌该、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至中符,卻和暖如春姜胖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背淀散。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工右莱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吧凉。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓隧出,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親阀捅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • OkHttp源碼的samples的簡(jiǎn)單使用的示例: public static void main(String....
    _warren閱讀 724評(píng)論 0 1
  • 這篇文章主要講 Android 網(wǎng)絡(luò)請(qǐng)求時(shí)所使用到的各個(gè)請(qǐng)求庫(kù)的關(guān)系针余,以及 OkHttp3 的介紹饲鄙。(如理解有誤,...
    小莊bb閱讀 1,145評(píng)論 0 4
  • OkHttp源碼分析-同步篇 很早就想拿okhttp開刀了圆雁,這次就記一次使用OKhttp的網(wǎng)絡(luò)請(qǐng)求忍级。首先需要說明的...
    埃賽爾閱讀 972評(píng)論 1 2
  • 這段時(shí)間老李的新公司要更換網(wǎng)絡(luò)層,知道現(xiàn)在主流網(wǎng)絡(luò)層的模式是RxJava+Retrofit+OKHttp,所以老李...
    隔壁老李頭閱讀 32,702評(píng)論 51 405
  • 我想我已不需要它了伪朽!
    圈夢(mèng)閱讀 124評(píng)論 0 0