OkHttp3架構(gòu)分析

在OkHttp3中妻熊,其靈活性很大程度上體現(xiàn)在芯侥,可以intercept其任意一個(gè)環(huán)節(jié)躏将,而這個(gè)優(yōu)勢(shì)便是okhttp3整個(gè)請(qǐng)求響應(yīng)架構(gòu)體系的精髓所在:


image.png
  • 在OkHttp3中陌知,每一個(gè)請(qǐng)求任務(wù)都封裝為一個(gè)Call京闰,其實(shí)現(xiàn)為RealCall颜及。
  • 而所有的策略幾乎都可以通過(guò)OkHttpClient傳入
  • 所有全局策略與數(shù)據(jù)甩苛,除了存儲(chǔ)在允許上層訪問的OkHttpClient實(shí)例以外,還有一部分是存儲(chǔ)在只允許包可見的Internal.instance中(如連接池俏站、路由黑名單等)
  • OkHttp中用戶可傳入的interceptor分為兩類讯蒲,一類是全局interceptor,該類interceptor在請(qǐng)求開始之前最早被調(diào)用肄扎,另外一類為非網(wǎng)頁(yè)請(qǐng)求的networkInterceptor墨林,這類interceptor只有在非網(wǎng)頁(yè)請(qǐng)求中會(huì)被調(diào)用,并且是在組裝完成請(qǐng)求之后犯祠,真正發(fā)起請(qǐng)求之前被調(diào)用(這塊具體可以參看RealCall#getResponseWithInterceptorChain()方法)
  • 整個(gè)請(qǐng)求過(guò)程通過(guò)RealInterceptorChain#proceed來(lái)連接旭等,在每個(gè)interceptor中調(diào)用下一個(gè)interceptor來(lái)完成整個(gè)請(qǐng)求流程,并且在回到當(dāng)前interceptor后完成響應(yīng)處理
  • 在異步請(qǐng)求中衡载,我們通過(guò)Callback來(lái)獲得簡(jiǎn)單清晰的請(qǐng)求回調(diào)(onFailure搔耕、onResponse)
  • 在OkHttpClient中,我們可以傳入EventListener的工廠方法痰娱,為每一個(gè)請(qǐng)求創(chuàng)建一個(gè)EventListener弃榨,來(lái)接收非常細(xì)的事件回調(diào)
image.png

OkHttp3中的線程池

OkHttp 中的對(duì)所有的任務(wù)采用 NamedRunnable,約束每個(gè)執(zhí)行單元給出對(duì)應(yīng)的業(yè)務(wù)名稱梨睁,以便于線程維護(hù)鲸睛。

1.異步請(qǐng)求線程池-OkHttp Dispatcher

  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;
  }

  • 該線程池與Android下的 Executors.newCachedThreadPool() 比較類似;
  • 無(wú)任務(wù)上限而姐,自動(dòng)回收閑置60s的線程腊凶,適用于大量耗時(shí)較短的任務(wù)划咐;
  • 雖然線程池?zé)o任務(wù)上限拴念,但是Dispatcher對(duì)入口enqueue()進(jìn)行了把關(guān),最大的異步任務(wù)數(shù)默認(rèn)是64褐缠,同一個(gè)主機(jī)默認(rèn)是5政鼠,當(dāng)然這兩個(gè)默認(rèn)值是可以修改的,Dispatcher提供的修改接口队魏;
okHttpClient.dispatcher().setMaxRequests(128);
okHttpClient.dispatcher().setMaxRequestsPerHost(10);

  • 通過(guò)兩個(gè)雙端隊(duì)列來(lái)維護(hù)準(zhǔn)備執(zhí)行的任務(wù)和正在執(zhí)行的任務(wù):Deque<AsyncCall> readyAsyncCalls, Deque<AsyncCall> runningAsyncCalls公般;

  • 在每個(gè)任務(wù)結(jié)束時(shí),都會(huì)檢查 readyAsyncCalls 是否有任務(wù)胡桨,在條件滿足的情況下官帘,按照先進(jìn)先出的原則將任務(wù)移動(dòng)到 runningAsyncCalls中,并在線程池中執(zhí)行昧谊;

image.png

2.連接池清理線程池-OkHttp ConnectionPool

/**
* Background threads are used to cleanup expired connections. There will be at most a single
* thread running per connection pool. The thread pool executor permits the pool itself to be
* garbage collected.
*/
private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,
    Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
    new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp ConnectionPool", true));

  • 該線程池用來(lái)清理長(zhǎng)時(shí)間閑置的和泄漏的連接刽虹;
  • 該線程池本身無(wú)任務(wù)上限,線程閑置60s自動(dòng)回收呢诬;
  • 雖然任務(wù)無(wú)上限涌哲,但其通過(guò) cleanupRunning 標(biāo)記來(lái)控制只有一個(gè)線程在運(yùn)行胖缤,當(dāng)連接池中沒有連接后才會(huì)被重新設(shè)置為 false;
void put(RealConnection connection) {
    assert (Thread.holdsLock(this));
    if (!cleanupRunning) {
        cleanupRunning = true;
        executor.execute(cleanupRunnable);
    }
    connections.add(connection);
}

  • 次工作線程會(huì)不斷地清理,當(dāng)清理完一遍后超時(shí)連接后阀圾,根據(jù)當(dāng)前連接池中最近的下一個(gè)空閑超時(shí)連接計(jì)算出一個(gè)阻塞時(shí)間并阻塞哪廓,直到連接池中沒有任何連接才結(jié)束,并將 cleanupRunning 設(shè)為 false;

  • 在每次有連接加入連接池時(shí)初烘,如果當(dāng)前沒有清理任務(wù)運(yùn)行涡真,會(huì)加入一個(gè)清理任務(wù)到到線程池中執(zhí)行;

void put(RealConnection connection) {
    assert (Thread.holdsLock(this));
    if (!cleanupRunning) {
        cleanupRunning = true;
        executor.execute(cleanupRunnable);
    }
    connections.add(connection);
  }

image.png

3. 緩存整理線程池-OkHttp DiskLruCache

// Use a single background thread to evict entries.
Executor executor = new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<Runnable>(), Util.threadFactory("OkHttp DiskLruCache", true));

  • 該線程池用于整理本地請(qǐng)求緩存數(shù)據(jù);
  • 緩存的整理包含: 達(dá)到閥值大小的文件肾筐,刪除最近最少使用的記錄综膀,在有關(guān)操作達(dá)到一定數(shù)量以后對(duì)記錄進(jìn)行重建;
  • 最大運(yùn)行線程數(shù)1局齿,無(wú)需考慮線程安全問題剧劝,自動(dòng)回收閑置60s的線程;

4. HTTP2異步事務(wù)線程池-OkHttp Http2Connection

  • HTTP2采用了多路復(fù)用抓歼,因此需要維護(hù)連接有效性讥此,本線程池就是用于維護(hù)相關(guān)的各類HTTP2事務(wù);
  • 線程池本身無(wú)任務(wù)上限,自動(dòng)回收閑置60s的線程;
  • 每一個(gè)HTTP2連接都有這么一個(gè)線程池存在;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谣妻,一起剝皮案震驚了整個(gè)濱河市萄喳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蹋半,老刑警劉巖他巨,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異减江,居然都是意外死亡染突,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門辈灼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)份企,“玉大人,你說(shuō)我怎么就攤上這事巡莹∷局荆” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵降宅,是天一觀的道長(zhǎng)骂远。 經(jīng)常有香客問我,道長(zhǎng)腰根,這世上最難降的妖魔是什么激才? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上贸营,老公的妹妹穿的比我還像新娘吨述。我一直安慰自己,他們只是感情好钞脂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布揣云。 她就那樣靜靜地躺著,像睡著了一般冰啃。 火紅的嫁衣襯著肌膚如雪邓夕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天阎毅,我揣著相機(jī)與錄音焚刚,去河邊找鬼。 笑死扇调,一個(gè)胖子當(dāng)著我的面吹牛矿咕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狼钮,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼碳柱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了熬芜?” 一聲冷哼從身側(cè)響起莲镣,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涎拉,沒想到半個(gè)月后瑞侮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鼓拧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年半火,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毁枯。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡慈缔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出种玛,到底是詐尸還是另有隱情,我是刑警寧澤瓤檐,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布赂韵,位于F島的核電站,受9級(jí)特大地震影響挠蛉,放射性物質(zhì)發(fā)生泄漏祭示。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一谴古、第九天 我趴在偏房一處隱蔽的房頂上張望质涛。 院中可真熱鬧稠歉,春花似錦、人聲如沸汇陆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)毡代。三九已至阅羹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間教寂,已是汗流浹背捏鱼。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留酪耕,地道東北人导梆。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像迂烁,于是被迫代替她去往敵國(guó)和親问潭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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

  • 在OkHttp3中婚被,其靈活性很大程度上體現(xiàn)在狡忙,可以intercept其任意一個(gè)環(huán)節(jié),而這個(gè)優(yōu)勢(shì)便是okhttp3整...
    Jdqm閱讀 24,754評(píng)論 4 43
  • 參考資源 官網(wǎng) 國(guó)內(nèi)博客 GitHub官網(wǎng) 鑒于一些關(guān)于OKHttp3源碼的解析文檔過(guò)于碎片化址芯,本文系統(tǒng)的灾茁,由淺入...
    風(fēng)骨依存閱讀 12,512評(píng)論 11 82
  • OKHttp牛逼之處 1.支持HTTP2/SPDY黑科技 --->okHttp中分包就分為Http1 和Http2...
    河里的枇杷樹閱讀 231評(píng)論 0 0
  • 有道云筆記markdown語(yǔ)法 一、在Markdown中谷炸,如果想將一段文字被定義為標(biāo)題北专,只需要在這段文字前面加上 ...
    yxinmin閱讀 245評(píng)論 0 0
  • 【第22天】 “虛靈頂勁,氣沉丹田旬陡。不偏不倚拓颓,忽隱忽現(xiàn)∶杳希” 身法要領(lǐng)驶睦。氣順,需上下貫通匿醒,頭頂百會(huì)有向上領(lǐng)起之意场航,但...
    UniverseArtwork閱讀 185評(píng)論 0 0