Okhttp 基礎(chǔ)知識(shí)導(dǎo)圖
Okhttp 使用
1兢哭,創(chuàng)建一個(gè)客戶端领舰。
2,創(chuàng)建一個(gè)請(qǐng)求迟螺。
3冲秽,發(fā)起請(qǐng)求(入?yún)⒒卣{(diào))。
Request request = new Request.Builder().url( "http://xxxxx").build();
//創(chuàng)建客戶端
OkHttpClient mOkHttpClient= new OkHttpClient.Builder()
.connectTimeout(30000, TimeUnit.MICROSECONDS)
.readTimeout(30000, TimeUnit.MICROSECONDS)
.writeTimeout(30000, TimeUnit.MICROSECONDS).build();
//創(chuàng)建請(qǐng)求
Call mCall= mOkHttpClient.newCall(request);
//請(qǐng)求+回調(diào)
mCall.enqueue(new Callback() {
@Override
public void onFailure(Call arg0, IOException arg1) {
}
@Override
public void onResponse(Call arg0, Response arg1) throws IOException {
}
});
一矩父、任務(wù)分發(fā)
網(wǎng)絡(luò)請(qǐng)求不能占用主線程資源锉桑,在多個(gè)請(qǐng)求并發(fā)條件下,需要一個(gè)管理器實(shí)現(xiàn)任務(wù)分發(fā)窍株,將任務(wù)交給線程池民轴。
1攻柠,RealCall 類
Request 類是一個(gè)請(qǐng)求實(shí)體,配置 url后裸,組裝 Header瑰钮,請(qǐng)求體RequestBody, method 支持 GET微驶、HEAD浪谴、POST、DELETE因苹、PUT苟耻、PATCH。
每個(gè) Request 實(shí)體創(chuàng)建一個(gè) RealCall 對(duì)象容燕,負(fù)責(zé)一個(gè)具體請(qǐng)求的 http 事務(wù)梁呈。
@Override
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
Call 接口,內(nèi)部工廠 Call.Factory 的 newCall() 方法創(chuàng)建蘸秘,OkHttpClient 類實(shí)現(xiàn)工廠接口官卡,創(chuàng)建 RealCall。
RealCall 類同步方法醋虏。
@Override
public Response execute() throws IOException {
synchronized (this) {
...
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();//同步寻咒,耗時(shí)處
return result;
} finally {
client.dispatcher().finished(this);
}
}
異步方法。
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
...
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
execute() 方法颈嚼,同步請(qǐng)求需要自己實(shí)現(xiàn)線程池毛秘。enqueue() 方法,創(chuàng)建一個(gè)異步任務(wù)阻课,交給分發(fā)者叫挟,Dispatcher 類分發(fā),(同步或異步)限煞。
2抹恳,Dispatcher 分發(fā)者
Dispatcher 類控制多個(gè) http 請(qǐng)求的節(jié)奏,負(fù)責(zé) RealCall 的并發(fā)署驻,管理(等待/運(yùn)行)隊(duì)列奋献,線程池調(diào)度。
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
同步分發(fā)旺上,將 RealCall 對(duì)象加入同步隊(duì)列瓶蚂,表示 RealCall 正在執(zhí)行。
synchronized void enqueue(AsyncCall call) {
//maxRequests=64宣吱,maxRequestsPerHost=5
if (runningAsyncCalls.size() < maxRequests &&
runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);//加入運(yùn)行隊(duì)列
executorService().execute(call);//線程池執(zhí)行任務(wù)
} else {
readyAsyncCalls.add(call);
}
}
異步分發(fā)窃这,maxRequests:最大請(qǐng)求數(shù)量,maxRequestsPerHost:每個(gè)主機(jī)最大并發(fā)請(qǐng)求數(shù)量征候。
滿足運(yùn)行時(shí)杭攻,將 AsyncCall (Runnable 任務(wù)洒试,RealCall 內(nèi)部類),加入運(yùn)行隊(duì)列朴上,派發(fā)線程池處理垒棋,不滿足運(yùn)行時(shí),加入等待隊(duì)列痪宰。
3叼架,請(qǐng)求結(jié)束
每次(同步/異步)請(qǐng)求完成時(shí),在 try/finally() 方法結(jié)束衣撬,Dispatcher 類的 finished()方法乖订。
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//同步隊(duì)列刪除RealCall,異步運(yùn)行隊(duì)列刪除AsyncCall任務(wù)
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();//異步promoteCalls參數(shù)是true
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
異步請(qǐng)求時(shí)具练,繼續(xù)查詢等待隊(duì)列中的請(qǐng)求乍构。
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return;
if (readyAsyncCalls.isEmpty()) return;
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();//滿足條件,等待隊(duì)列刪除
runningAsyncCalls.add(call);//加入運(yùn)行中隊(duì)列
executorService().execute(call);//開(kāi)始執(zhí)行
}
if (runningAsyncCalls.size() >= maxRequests) return;
}
}
遍歷等待隊(duì)列的任務(wù)扛点,滿足運(yùn)行條件時(shí)哥遮,從等待隊(duì)列刪除,加入運(yùn)行隊(duì)列陵究,派發(fā)線程池眠饮。
二、線程池管理
分發(fā)者內(nèi)部閥值[0, Integer.MAX_VALUE]的緩存線程池铜邮。
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;
}
- 不保留 corePoolSize 核心線程仪召,最大可創(chuàng)建線程 MAX_VALUE。
- 工作線程 keepAliveTime 設(shè)置60存活期線程復(fù)用松蒜。
- SynchronousQueue 阻塞隊(duì)列不存儲(chǔ)元素扔茅,管道。
大量http請(qǐng)求并發(fā)時(shí)秸苗,線程池啟動(dòng)多個(gè)工作線程(臨時(shí)線程)召娜,確保每個(gè)任務(wù)都有線程及時(shí)處理。
線程執(zhí)行主體是 NamedRunnable 類 run() 方法难述,子類是運(yùn)行隊(duì)列中的 AsyncCall任務(wù)類萤晴,實(shí)現(xiàn) execute() 抽象方法吐句。
AsyncCall 構(gòu)造方法胁后,傳入外部Callback回調(diào)對(duì)象。
@Override
protected void execute() {
boolean signalledCallback = false;
try {
//觸發(fā)RealCall類的方法嗦枢,AsyncCall任務(wù)類定義在RealCall類內(nèi)部攀芯。
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) {
} finally {
//異步請(qǐng)求結(jié)束后finish。
client.dispatcher().finished(this);
}
}
外部 RealCall 類的 getResponseWithInterceptorChain() 方法文虏,(同步/異步)請(qǐng)求耗時(shí)操作侣诺,返回 Response 實(shí)體殖演。
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
創(chuàng)建了一系列攔截器,鏈?zhǔn)教幚砟暝В彺媾烤谩⑦B接都通過(guò)攔截器鏈的節(jié)點(diǎn)實(shí)現(xiàn)。搔确、
三彼棍、攔截器
攔截器順序
客戶端自定義攔截器
retryAndFollowUpInterceptor 攔截器
BridgeInterceptor 橋接
CacheInterceptor 緩存
ConnectInterceptor 連接
networkInterceptors 網(wǎng)絡(luò)
CallServerInterceptor 數(shù)據(jù)流讀寫
RealInterceptorChain 類是在攔截器之間傳遞的節(jié)點(diǎn),第一次創(chuàng)建時(shí)膳算,index 初始是0座硕,入?yún)鬟f originalRequest 原始請(qǐng)求與攔截器列表。
在 RealInterceptorChain 類的 proceed() 方法涕蜂,開(kāi)始鏈?zhǔn)教幚砘遥脭r截器表中各層攔截處理 Request 請(qǐng)求和 Response 回復(fù)。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
..
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
//拋出異常
}
if (response == null) {
//拋出異常
}
return response;
}
查找攔截器鏈表 index 索引的 Interceptor机隙,新建 index++ 的 RealInterceptorChain 節(jié)點(diǎn)蜘拉,觸發(fā) Interceptor的intercept() 方法,傳遞新 Chain有鹿。
列表中每一個(gè) Interceptor 攔截器的 intercept() 方法诸尽。
- 處理 Request 請(qǐng)求
- Chain 節(jié)點(diǎn)的 proceed() 方法
- 處理 Response 答復(fù)
每一個(gè) Chain 節(jié)點(diǎn) proceed() 方法邏輯。
- 查找下一個(gè)攔截器
- 創(chuàng)建新 Chain 節(jié)點(diǎn)
- 攔截器 intercept() 方法印颤,傳入新節(jié)點(diǎn)
當(dāng) index++索引到達(dá)最后一個(gè)攔截器 CallServerInterceptor 時(shí)您机,真正向 Server 發(fā)送數(shù)據(jù),獲取 Response年局,然后遞歸一層層按原路返回际看。
攔截器列表前部分 Interceptor 優(yōu)先處理原始 Request,后部分優(yōu)先處理原始 Response矢否。
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
攔截器設(shè)計(jì)是一個(gè)遞歸調(diào)用過(guò)程仲闽,Chain 對(duì)象是鏈節(jié)點(diǎn),proceed() 方法處理時(shí)僵朗,創(chuàng)建 index++的 Chain 新節(jié)點(diǎn)赖欣,傳遞給下一個(gè)攔截器。
proceed() 方法流入 Request 請(qǐng)求验庙,流出 Response 答復(fù)顶吮,攔截器目的是層層截?cái)嗔魅肱c流出,先截流粪薛,加工處理悴了,再放流。
四、緩存設(shè)計(jì)
五湃交、連接池
六熟空、數(shù)據(jù)流
任重而道遠(yuǎn)