OkHttp( 3.9.0-SNAPSHOT)源碼解析

OkHttp源碼的samples的簡單使用的示例:

public static void main(String... args) throws Exception{

OkHttpClient client=new OkHttpClient();

// Create request for remote resource.

Request request=new Request.Builder()

.url(ENDPOINT)

.build();

// Execute the request and retrieve the response.

Response response=client.newCall(request).execute();

// Deserialize HTTP response to concrete type.

ResponseBody body=response.body();

Listcontributors=CONTRIBUTORS_JSON_ADAPTER.fromJson(body.source());

body.close();

......

}

靜態常量

OkHttpClient開始就定義了兩個靜態常量,這兩個常量是與協議相關分別是DEFAULT_CONNECTION_SPECS和DEFAULT_PROTOCOLS。

靜態代碼塊

接下來看OkHttpClient的static代碼塊主要就是創建了一個Internal的內部類對象。

接口

OkHttpClient實現了三個接口,分別是Cloneable,Call.Factory,WebSocket.Factory

重點在Call.Factory接口上,Call該接口的實例就是我么去執行請求網絡數據的對象,

Call中的主要方法

/** 返回該Call創建的Request請求對象 */

Request request();

/** 同步執行請求網絡數據,返回服務端響應結果*/

Response execute()throwsIOException;

/** 異步執行請求網絡數據的回調方法*/

void enqueue(Callback responseCallback);

/** 取消網絡請求*/

void cancel();

/** 判斷網絡請求是否被執行了*/

boolean isExecuted();

/** 判斷網絡請求是否被取消了*/

boolean isCanceled();

/**clone該方法是Cloneable接口中的方法,意義在于創建一個相同的請求對象*/

Call clone();

/**Factory內部接口就是創建Call的工廠接口,該接口定義的方法newCall需要傳入Request對象*/

interface Factory{

Call newCall(Request request);

}

成員變量

最重要的就是OkHttpClient,該類的成員變量中6個成員變量進行重點說明的

final Dispatcher dispatcher;

final List?interceptors;

final List?networkInterceptors;

final EventListener.Factory eventListenerFactory;

final @Nullable Cache cache;?

final @Nullable InternalCache internalCache;

1、同步請求過程解析

Response response=client.newCall(request).execute(); 這句代碼執行過程:

(1)client.newCall(request)

第一步:上面提到OkHttpClient的三個接口中有個Factory內部接口(創建Call的工廠接口),而Call對象有個實現類RealCall,其實newCall方法是RealCall執行自己的newRealCall方法創建了一個RealCall實例,該方法三個參數如下:

*@param client OkHttpClient對象

*@param originalRequest 之前傳入的那個原始請求對象

*@param forWebSocket 是否是WebSocket

RealCall call=newRealCall(client,originalRequest,forWebSocket);

第二步:上面提到OkHttpClient的6個成員變量中有個EventListener.Factory eventListenerFactory對象(也是個工廠接口,內部定義了一個create方法用于創建EventListener對象),上一步傳入了OkHttpClient對象,該對象已經創建完了eventListenerFactory實例,所以拿到該實例傳入call對象創建EventListener對象。

抽象類EventListener中有一大堆的網絡連接的監聽方法

call.eventListener=client.eventListenerFactory().create(call);

最后返回當前的Call對象

(2)call.execute()

@Override

publicResponse execute()throwsIOException{

? ? synchronized(this) {

? ? if(executed)throw newIllegalStateException("Already Executed");

? ? ?executed=true;

}

? ?captureCallStackTrace();

?try{

? ? ? ?client.dispatcher().executed(this);

? ? ? Response result=getResponseWithInterceptorChain();

? ? ? if(result==null)throw newIOException("Canceled");

? ? ? ?returnresult;

? ? ? }finally{

? ? ? ?client.dispatcher().finished(this);

? ?}

}

2.1)call中的execute方法中的client.dispatcher().executed(this);

由于execute是同步執行網絡請求所以要用關鍵字synchronized,

synchronized(this) {

? ? if(executed)throw newIllegalStateException("Already Executed");

? ?executed=true;

}

之后再執行captureCallStackTrace()方法,放入堆棧進行追蹤捕捉。

client.dispatcher()是獲得上面OkHttpClient的成員變量Dispatcher dispatcher,注意啦Dispatcher中的方法基本都是同步,用的Synchronized修飾的方法。為了分析清楚這里插一段Dispatcher的說明。

Dispatcher中維護著執行發送請求的線程池,所有的請求都是放在請求隊列中的總共有三個隊列readyAsyncCalls(準備的異步請求隊列),runningAsyncCalls(正在在執行的異步請求還包括被中斷的),runningSyncCalls(正在在執行的異步請求還包括被中斷的)

private final Deque<AsyncCall> readyAsyncCalls=newArrayDeque<>();

private final Deque<AsyncCall> runningAsyncCalls=newArrayDeque<>();

private final Deque<RealCall> runningSyncCalls=newArrayDeque<>();

RealCall和AsyncCall的關系通過Dispatcher類的導入代碼可以看出

import okhttp3.RealCall.AsyncCall; ? // AsyncCall其實就是RealCall的內部類

具體實現如下:

final class AsyncCall extends NamedRunnable{

private final Callback responseCallback;

// 構造時需要傳入一個Callback接口,也就是返回給我們成功失敗的回調方法

AsyncCall(Callback responseCallback) { ?

? ?super("OkHttp %s",redactedUrl());

? ?this.responseCallback=responseCallback;

}

String host() {

? ? return originalRequest.url().host();

}

Request request() {

? ? ?return originalRequest;

}

RealCall ?get() {

? ? return RealCall.this;

}

@Override

protected void execute() {

? ? ? ? ? boolean signalledCallback=false;

? ?try{

? ? ? ? ? Response response=getResponseWithInterceptorChain();

? ? ? ? ? if(retryAndFollowUpInterceptor.isCanceled()) {

? ? ? ? ? signalledCallback=true;

? ? ? ? ? responseCallback.onFailure(RealCall.this,newIOException("Canceled"));

? ? ? }else{

? ? ? ? ? signalledCallback=true;

? ? ? ? ? responseCallback.onResponse(RealCall.this,response);

? ? ?}

? }catch(IOException e) {

? ? ? ?if(signalledCallback) {

? ? ? ?// Do not signal the callback twice!

? ? ? ? Platform.get().log(INFO,"Callback failure for "+toLoggableString(),e);

? ? }else{

? ? ? ?responseCallback.onFailure(RealCall.this,e);

? ?}

? ? ? }finally{

? ? ? ? client.dispatcher().finished(this);

? ? ? }

? ?}

}

dispatcher中erexecuted方法的具體實現

// ?加入同步執行隊列

synchronized void executed(RealCall call) {

? runningSyncCalls.add(call);

}

2.2)Response result=getResponseWithInterceptorChain();

下面回過頭去看RealCall的execute方法中client.dispatcher().executed(this);執行結束后的代碼Response result=getResponseWithInterceptorChain();

為了分析清楚這里插一段Interceptor的說明

Response getResponseWithInterceptorChain()throwsIOException{

//創建一個存放攔截器的集合,最后傳入 newRealInterceptorChain對象中

? ?List<Intercepter> ?interceptors=newArrayList<>();

// client.interceptors() (自定義的攔截器, 在call api的前的攔截) - > //retryAndFollowUpInterceptor (實現請求重試)

? ?interceptors.addAll(client.interceptors());

// 重定向攔截器

? ?interceptors.add(retryAndFollowUpInterceptor);

// 橋接攔截器(處理header 、cookie 等)

? ?interceptors.add(newBridgeInterceptor(client.cookieJar()));

// 緩存攔截器(處理 cache)

? ?interceptors.add(newCacheInterceptor(client.internalCache()));

// 連接攔截器(負責建立連接)

? ?interceptors.add(newConnectInterceptor(client));

? ?if(!forWebSocket) {

// 自定義網絡攔截器(此時已建立連接)

? ? ?interceptors.addAll(client.networkInterceptors());

? }

// 服務請求攔截器(發起請求、接收響應)

? ?interceptors.add(newCallServerInterceptor(forWebSocket));

Interceptor.Chain chain = new RealInterceptorChain(interceptors,null,null,null,0,originalRequest,this,eventListener); ? return chain.proceed(originalRequest);

}?

上面的RealInterceptorChain方法具體實現。在RealCall里的getResponseWithInterceptorChain方法里,創建了一個RealInterceptorChain對象,調用proceed(),在interceptor的intercept()方法里又調用proceed(),明顯形成了一個遞歸,像鏈表一下一個一個遞歸傳遞并且做相應的攔截處理。

RealInterceptorChain next=newRealInterceptorChain(interceptors,streamAllocation,httpCodec,

connection,index+1,request,call,eventListener);

Interceptor interceptor=interceptors.get(index);

Response response=interceptor.intercept(next);

最后一個攔截器返回處理的Response,也就是服務器端返回的結果,并且在代碼中加了許多的判斷如:this.httpCodec!=null 意思就是還沒有攔截鏈執行完。interceptor必須執行一次proceed()方法,否則會拋異常。

RealInterceptorChain + Interceptor實現了裝飾器模式,實現了請求/響應的串式或流式處理。只不過內層裝飾器不是外層裝飾器的成員變量,而是接口方法中創建的臨時變量。

在ConnectInterceptor之后的攔截器必須滿足:request的url要一致,interceptor必須執行一次proceed()。這樣子做是為了保證遞推的正常運作。而對與client.interceptors是在ConnectInterceptor之前的攔截器,可以不用必須執行一次proceed()。可以實現直接返回虛擬的response用于是測試等功能。

這幾個Interceptor的職責:

RetryAndFollowUpInterceptor --->創建StreamAllocation對象,處理http的redirect,出錯重試。對后續Interceptor的執行的影響:修改request及StreamAllocation。

BridgeInterceptor-------------->補全缺失的一些http header。對后續Interceptor的執行的影響:修改request。

CacheInterceptor-------------->處理http緩存。對后續Interceptor的執行的影響:若緩存中有所需請求的響應,則后續Interceptor不再執行。

ConnectInterceptor------------>借助于前面分配的StreamAllocation對象建立與服務器之間的連接,并選定交互所用的協議是HTTP 1.1還是HTTP 2。對后續Interceptor的執行的影響:創建了httpStream和connection。

CallServerInterceptor----------->處理IO,與服務器進行數據交換。對后續Interceptor的執行的影響:為Interceptor鏈中的最后一個Interceptor,沒有后續Interceptor

2.3client.dispatcher().finished(this);?

dispatcher中finish方法的具體實現(注意第三個參數的差別)

/** Used by {@codeCall #execute} to signal completion.同步方法 */

void finished(RealCall call) {

? ? finished(runningSyncCalls,call,false);

}

/** Used by {@codeAsyncCall#run} to signal completion. 異步方法*/

void ?finished(AsyncCall call) {

? ? finished(runningAsyncCalls,call,true);

}

上面的finished(runningAsyncCalls,call,true);方法實現如下:

private?void finished(Dequecalls,T call,boolean promoteCalls) {

? ?int ?runningCallsCount;

? ?Runnable idleCallback;

? synchronized(this) {

? ? if (!calls.remove(call) ) throw newAssertionError("Call wasn't in-flight!");

? ? ? if(promoteCalls) ?promoteCalls(); // 異步Call數量多時需要維護隊列,而不是立即執.行,所以要加入到runningAsyncCalls中

? ? ? ?runningCallsCount = runningCallsCount();

? ? ? ?idleCallback = this.idleCallback;

? }

? if(runningCallsCount==0&&idleCallback!=null) {

? ? idleCallback.run();

? }

}

上面promoteCalls方法的具體實現如下:

private int maxRequests=64;

private int maxRequestsPerHost=5;

private void promoteCalls() {

? ? if(runningAsyncCalls.size()>=maxRequests) return;// 已經達到最大容器.

? ? ?if ( readyAsyncCalls.isEmpty() ) return; // 隊列為空

? ? ? ? for(Iterator?i=readyAsyncCalls.iterator();i.hasNext();) { ?// 遍歷取出

? ? ? ? ? AsyncCall call=i.next(); ?

?// 當正在執行的任務總數及相同host下的任務數小于最大值時,直接執行當前請求,而任務數超過限定時,將其加入等待隊列。

? ? ? ? ? if ( runningCallsForHost(call) < maxRequestsPerHost ){?

? ? ? ? ? ? ?i.remove();

? ? ? ? ? ? runningAsyncCalls.add(call);

? ? ? ? ? ? executorService().execute(call);

? ? ? ? ? }

? ? ?}

? ? if ( runningAsyncCalls.size()>=maxRequests ) return;// Reached max capacity.

?}

}

還可以通setMaxRequests()設置同時允許執行的最大請求數,以及setMaxRequestsPerHost()設置相同host下最多運行的請求數。從源碼中看出OkHttpClient用了許多的Budiler設計模式,幾個重要的類Response、Request、OkHttpClient。

2、異步請求過程解析

RealCall的enqueue方法,其中遇到的大部分方法在同步請求中有分析就不贅述了。主要講一下異步網絡請求的流程

@Override

public voidenqueue(Callback responseCallback) {

? synchronized(this) {

? ? ? if(executed)throw newIllegalStateException("Already Executed"); ?

? ? ?executed=true;

?}

? ? captureCallStackTrace();

? ? client.dispatcher().enqueue(newAsyncCall(responseCallback));

}

上面client.dispatcher().enqueue(newAsyncCall(responseCallback));中Dispatcher的enqueue方法

synchronized void enqueue(AsyncCall call) {

// 如果正在執行異步請求的隊列沒有超過最大請求數量,并且有沒有超過每個主機允許的最大訪問量

// 就將請求加入到正在執行異步請求的隊列中,否則就加入到準備異步請求的隊列中去

? if(runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost

? ? ?runningAsyncCalls.add(call);?

? ? ?executorService().execute(call);

? ?}else{

? ? ? readyAsyncCalls.add(call);

? ?}


異步請求返回是通過接口回調的具體實現如下:

final classAsyncCallextendsNamedRunnable{

private finalCallback responseCallback;

AsyncCall(Callback responseCallback) {

? ? super("OkHttp %s",redactedUrl());

? ? this.responseCallback=responseCallback;

}

String host() {

? ? return ?originalRequest.url().host();

}

Request request() {

? return originalRequest;

}

RealCall get() {

? ? return ?RealCall.this;

}

@Override

protected voidexecute() {

? ?booleansignalledCallback=false;

try{

? ? Response response=getResponseWithInterceptorChain();

? ? if (retryAndFollowUpInterceptor.isCanceled() ) {

? ? ? ?signalledCallback=true;

? ? ? ?responseCallback.onFailure(RealCall.this,newIOException("Canceled"));

? ? }else{

? ? ? signalledCallback=true;

? ? ? responseCallback.onResponse(RealCall.this,response);

}

? }catch(IOException e) {

? ? ? ? if(signalledCallback) {

? ? ? ? ? // Do not signal the callback twice!

? ? ? ? ? Platform.get().log(INFO,"Callback failure for "+toLoggableString(),e);

? ? ? }else{

? ? ? ? ? responseCallback.onFailure(RealCall.this,e);

? ? ? ?}

? ?}finally{

? ? ?client.dispatcher().finished(this);

? ?}

?}

}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容