OkHttp源碼解讀總結(三)—>OkHttp同步請求源碼解析
標籤(空格分隔): OkHttp源碼 學習筆記
前言
- 以下的相關知識總結是通過慕課網的相關學習和自己的相關看法,如果有需要的可以去查看一下慕課網的相關教學,感覺還可以。
第一步創建的OkHttpClient客戶端
創建這個OkHttpClient並設置相關的參數,需要用到他的內部類的Builder的build()方法。首先我們看下這個builder的構造方法(無參的構造方法)
public Builder() {
//主要的幾個參數
//dispatcher對象 http請求的分發器 主要是作用於異步請求是需要直接處理還是進行緩存等待(緩存)
dispatcher = new Dispatcher();
//連接池 客戶端和服務器之間的可以看做一個Connection 而每一個Connection我們都會把他放在這個連接池中 進行統一管理 (1)如果URL相同的時候可以選擇複用 (2)進行相關設置,是保持連接還是選擇以後複用管理
connectionPool = new ConnectionPool();
//默認的超時相關時間
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}
第二步創建Request請求報文信息類
這個Request對象的創建也是一個建造者模式來構建的。通過鏈式調用指定請求方法,指定頭部,請求參數等等設置
//這個比較簡單
public Builder() {
設置請求方法爲GET請求
this.method = "GET";
//創建了一個Headers的內部類 用於保存頭部信息
this.headers = new Headers.Builder();
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
//可以看到這個build方法就是把當前的Builder對象傳遞到Request裏面 創建Request對象 也就是說 通過這個build()方法之後,就能把我們已經配置好的Builder的中的請求方式,請求地址,頭部 都賦值給我們的Request對象
return new Request(this);
}
所以可以看下Request這個構造方法 我們可以看到在構造方法中,通過傳遞進來的Builder這個實例來進行相關變量的賦值
Request(Builder builder) {
this.url = builder.url; //網絡地址
this.method = builder.method; //請求方式
this.headers = builder.headers.build(); //頭部
this.body = builder.body; //body
this.tag = builder.tag != null ? builder.tag : this;
}
3、創建Http請求的實際Call對象
Call requestCall = getOkHttpClient().newCall(request);
@Override
public Call newCall(Request request) {
//因爲Call是一個接口 他的實際操作都是在他的實現類中進行 也就是RealCall這個實現類
return RealCall.newRealCall(this, request, false /* for web socket */);
}
Call請求的實現類RealCall
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
//創建了實現類的對象 通過okhttpclient request
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
RealCall的構造方法
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
//持有傳入進來的兩個實例
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
//創建一個重定向攔截器 以後會進行講解
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
不管是同步還是異步,都是通過newCall()這個方法創建的RealCall對象來進行相應的操作
4、execute()方法進行同步請求
Response response = requestCall.execute();
RealCall的實現類覆寫的這個execute()方法
@Override public Response execute() throws IOException {
//同步
synchronized (this) {
//判斷這個是否被執行過 一個http請求只能執行一次 如果已經執行了 那麼就會拋出異常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//捕捉異常堆棧信息
captureCallStackTrace();
//監聽事件開啓
eventListener.callStart(this);
try {
//核心代碼
client.dispatcher().executed(this);
//當把請求call放置到同步請求隊列當中 進行請求之後 我們通過getResponseWithInterceptorChain()這個方法來獲取相應Response 這個之後再總結(攔截器)
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
//結束
client.dispatcher().finished(this);
}
}
client.dispatcher()
public Dispatcher dispatcher() {
return dispatcher;
}
client.dispatcher().executed(this)
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); //這個是在Dispatcher類中定義的 同步請求隊列 可以看出 還定義的有
/** Ready async calls in the order they'll be run. */
//異步就緒隊列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
//異步執行隊列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
synchronized void executed(RealCall call) {
//添加到同步請求隊列
runningSyncCalls.add(call);
}
補充
client.dispatcher().finished(this)方法;
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
//把我們當前正在執行的請求傳遞過來 然後把這個請求從同步請求隊列中進行移除(如果能移除)
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//同步不走 因爲始終傳入的是false
if (promoteCalls) promoteCalls();
//計算目前還在進行的請求
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
//如果正在請求的數爲0 沒有可運行的請求 並且idleCallback不爲空
if (runningCallsCount == 0 && idleCallback != null) {
//run方法
idleCallback.run();
}
}
//返回正在執行的異步和同步請求總和
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
可以看出這個Dispatcher分發器在同步請求中做的很簡單,那就是保存和移除同步請求。對於異步請求,Dispatcher就需要做的好多工作了。