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