目錄介紹
- 01.有哪些重要的類
- 02.OKHttpClient類
- 03.Request和Response類
- 04.Call接口類說明
- 05.RealCall類說明
- 06.Dispatcher類說明
- 07.主要流程圖
01.有哪些重要的類
- OKHttpClient類
- Request類和Response類
- Call類和RealCall類
- Dispatcher類
02.OKHttpClient類說明
- 1、裏面包含了很多對象,其實OKhttp的很多功能模塊都包裝進這個類,讓這個類單獨提供對外的API,這種外觀模式的設計十分的優雅。外觀模式。
- 2、而內部模塊比較多,就使用了Builder模式(建造器模式)。Builder模式(建造器模式)
- 3、它的方法只有一個:newCall.返回一個Call對象(一個準備好了的可以執行和取消的請求)。
03.Request和Response類
- Request類說明
- Request抽象成請求數據
- Request包括Headers和RequestBody,而RequestBody是abstract的,他的子類是有FormBody(表單提交的)和MultipartBody(文件上傳),分別對應了兩種不同的MIME類型
FormBody :"application/x-www-form-urlencoded" MultipartBody:"multipart/"+xxx.
- Response類說明
- Response抽象成響應數據
- Response包括Headers和RequestBody,而ResponseBody是abstract的,所以他的子類也是有兩個:RealResponseBody和CacheResponseBody,分別代表真實響應和緩存響應。
- 關於Headers說明,頭部信息不是隨便寫的
- OKHttp的封裝類Request和Response爲了應用程序編程方便,會把一些常用的Header信息專門提取出來,作爲局部變量。比如contentType,contentLength,code,message,cacheControl,tag…它們其實都是以name-value對的形勢,存儲在網絡請求的頭部信息中。
04.Call接口類說明
- Get或者Post請求,顯示用builder構建了Request對象,然後執行了OKHttpClient.java的newCall方法,那麼咱們就看看這個newCall裏面都做什麼操作?
//準備將來某個時候執行的{@code請求}。 @Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); }
- Call類詳解
- 有道詞典翻譯該類註釋:調用是準備執行的請求。call可以取消。由於此對象表示單個請求/響應對(流),因此不能執行兩次。
- 主要是HTTP請求任務封裝
- 可以說我們能用到的操縱基本上都定義在這個接口裏面了,所以也可以說這個類是OKHttp類的核心類了。我們可以通過Call對象來操作請求,同步請求execute,異步請求enqueue,這兩個想必都是很熟悉呢。而Call接口內部提供了Factory工廠方法模式(將對象的創建延遲到工廠類的子類去進行,從而實現動態配置)。
- Call接口提供了內部接口Factory(用於將對象的創建延遲到該工廠類的子類中進行,從而實現動態的配置)。
- Call類接口
- 繼承Cloneable類,表明是可以clone的。接口中幾個方法用的都非常多……
public interface Call extends Cloneable { Request request(); Response execute() throws IOException; void enqueue(Callback responseCallback); void cancel(); boolean isExecuted(); boolean isCanceled(); Call clone(); interface Factory { Call newCall(Request request); } }
05.RealCall類說明
5.1 RealCall構造
- RealCall類構造創建對象
- 在源碼中,OKHttpClient實現了Call.Factory接口,返回了一個RealCall對象。那我們就來看下RealCall這個類。代碼如下所示:
@Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); } static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { // Safely publish the Call instance to the EventListener. RealCall call = new RealCall(client, originalRequest, forWebSocket); call.eventListener = client.eventListenerFactory().create(call); return call; }
- 1、OkHttpClient的newCall方法裏面new了RealCall的對象,但是RealCall的構造函數需要傳入一個OKHttpClient對象和Request對象(PS:第三個參數false表示不是webSokcet)。因此RealCall包裝了Request對象。所以RealCall可以很方便地使用這兩個對象。
- 2、RealCall裏面的兩個關鍵方法是:execute 和 enqueue。分別用於同步和異步得執行網絡請求。
- 3、RealCall還有一個重要方法是:getResponseWithInterceptorChain,添加攔截器,通過攔截器可以將一個流式工作分解爲可配置的分段流程,既增加了靈活性也實現瞭解耦,關鍵還可以自有配置,非常完美。
5.2 execute方法調用
- client.newCall(request).execute();實際上執行的是RealCall的execute方法,現在咱們再回來看下RealCall的execute的具體實現
- 首先是判斷call是否執行過,可以看出每個Call對象只能使用一次原則。
@Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); eventListener.callStart(this); try { client.dispatcher().executed(this); 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); } }
- 然後接着看captureCallStackTrace方法
- RealCall的captureCallStackTrace() 又調用了Platform.get().getStackTraceForCloseable()。
- 其實是調用AndroidPlatform. getStackTraceForCloseable(String closer)方法。這裏就不詳細說了,後面詳細說。
- 然後retryAndFollowUpInterceptor.setCallStackTrace(),在這個方法裏面什麼都沒做就是set一個object進去。
- 綜上所示captureCallStackTrace()這個方法其實是捕獲了這個請求的StackTrace。
private void captureCallStackTrace() { Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()"); retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace); } public Object getStackTraceForCloseable(String closer) { if (logger.isLoggable(Level.FINE)) { return new Throwable(closer); // These are expensive to allocate. } return null; }
5.3 enqueue異步方法
- client.newCall(request).enqueue();實際上執行的是RealCall的enqueue方法,現在咱們再回來看下RealCall的enqueue的具體實現。
@Override public void enqueue(Callback responseCallback) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); eventListener.callStart(this); client.dispatcher().enqueue(new AsyncCall(responseCallback)); }
- 由於executed默認爲false,所以先進行判斷是否爲true,爲true則直接跑異常,沒有則設置爲true,可以看出executed這個是一個標誌,標誌這個請求是否已經正在請求中,合同步一樣先調用了captureCallStackTrace();然後調用 client.dispatcher().enqueue(new AsyncCall(responseCallback));client.dispatcher()返回的是Dispatcher對象所以實際調用的是Dispatcher的enqueue()
06.Dispatcher類說明
6.1 execute同步方法源碼分析
- 然後看一下關鍵性代碼,如下所示。
- 進入了第一個核心類—Dispatcher的的execute方法。
try { client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { eventListener.callFailed(this, e); throw e; } finally { //最後需要調用finished方法結束 client.dispatcher().finished(this); }
- 看下OKHttpClient的dispatcher()方法的具體內容
- 發現client.dispatcher()返回的是Dispatcher對象,那麼這個Dispatcher對象是何時創建的呢?
public Dispatcher dispatcher() { return dispatcher; }
- 在OkHttpClient.java裏面Build類裏面的構造函數裏面
- 默認執行Builder()放到時候就創建了一個Dispatcher
//OkHttpClient.java public static final class Builder { public Builder() { dispatcher = new Dispatcher(); } }
- 接着看看Dispatcher類中executed執行方法
- 裏面發現是runningSyncCalls執行了add方法,可以發現runningSyncCalls是ArrayDeque對象。
synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
- 查看dispatcher裏面怎麼定義runningSyncCalls的
- 原來runningSyncCalls是雙向隊列啊,突然發現Dispatcher裏面定義了三個雙向隊列,看下注釋,我們大概能明白readyAsyncCalls 是一個存放了等待執行任務Call的雙向隊列,runningAsyncCalls是一個存放異步請求任務Call的雙向任務隊列,runningSyncCalls是一個存放同步請求的雙向隊列。
/** 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<>(); /** Running synchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
- 接着看一下getResponseWithInterceptorChain源代碼
- 發現 new了一個ArrayList,然後就是不斷的add,後面 new了 RealInterceptorChain對象,最後調用了chain.proceed()方法。
Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List<Interceptor> interceptors = new ArrayList<>(); //添加開發者應用層自定義的Interceptor interceptors.addAll(client.interceptors()); //這個Interceptor是處理請求失敗的重試,重定向 interceptors.add(retryAndFollowUpInterceptor); //這個Interceptor工作是添加一些請求的頭部或其他信息 //並對返回的Response做一些友好的處理(有一些信息你可能並不需要) interceptors.add(new BridgeInterceptor(client.cookieJar())); //這個Interceptor的職責是判斷緩存是否存在,讀取緩存,更新緩存等等 interceptors.add(new CacheInterceptor(client.internalCache())); //這個Interceptor的職責是建立客戶端和服務器的連接 interceptors.add(new ConnectInterceptor(client)); if (!forWebSocket) { //添加開發者自定義的網絡層攔截器 interceptors.addAll(client.networkInterceptors()); } interceptors.add(new CallServerInterceptor(forWebSocket)); //一個包裹這request的chain Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); //把chain傳遞到第一個Interceptor手中 return chain.proceed(originalRequest); }
- 看下RealInterceptorChain的構造函數。可以發現這裏面僅僅只是一些賦值操作。
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call, EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) { this.interceptors = interceptors; this.connection = connection; this.streamAllocation = streamAllocation; this.httpCodec = httpCodec; this.index = index; this.request = request; this.call = call; this.eventListener = eventListener; this.connectTimeout = connectTimeout; this.readTimeout = readTimeout; this.writeTimeout = writeTimeout; }
- 跟蹤下chain.proceed()方法,看看做了什麼。
public interface Interceptor { Response intercept(Chain chain) throws IOException; interface Chain { Request request(); Response proceed(Request request) throws IOException; @Nullable Connection connection(); Call call(); } }
- 由於Interceptor是個接口,所以應該是具體實現類RealInterceptorChain的proceed實現。
public final class RealInterceptorChain implements Interceptor.Chain { @Override public Response proceed(Request request) throws IOException { return proceed(request, streamAllocation, httpCodec, connection); } public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException { if (index >= interceptors.size()) throw new AssertionError(); calls++; // If we already have a stream, confirm that the incoming request will use it. if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must retain the same host and port"); } // If we already have a stream, confirm that this is the only call to chain.proceed(). if (this.httpCodec != null && calls > 1) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must call proceed() exactly once"); } // Call the next interceptor in the chain. RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index + 1, request, call, eventListener, connectTimeout, readTimeout, writeTimeout); Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next); // Confirm that the next interceptor made its required call to chain.proceed(). if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) { throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once"); } // Confirm that the intercepted response isn't null. if (response == null) { throw new NullPointerException("interceptor " + interceptor + " returned null"); } if (response.body() == null) { throw new IllegalStateException( "interceptor " + interceptor + " returned a response with no body"); } return response; } }
- 看到在proceed方面裏面又new了一個RealInterceptorChain類的next對象,溫馨提示下,裏面的streamAllocation, httpCodec, connection都是null,所以這個next對象和chain最大的區別就是index屬性值不同chain是0.而next是1,然後取interceptors下標爲1的對象的interceptor。由從上文可知,如果沒有開發者自定義的Interceptor時,首先調用的RetryAndFollowUpInterceptor,如果有開發者自己定義的interceptor則調用開發者interceptor。
6.2 enqueue異步方法
- 先看call類中的代碼
- client.dispatcher()返回的是Dispatcher對象所以實際調用的是Dispatcher的enqueue()。
@Override public void enqueue(Callback responseCallback) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); eventListener.callStart(this); client.dispatcher().enqueue(new AsyncCall(responseCallback)); }
- 接着重點看一下client.dispatcher().enqueue方法操作了什麼
- 根據源碼和註釋大家可以看到如果正在執行的異步請求小於64,並且請求同一個主機小於5的時候就先往正在運行的隊列裏面添加這個call,然後用線程池去執行這個call,否則就把他放到等待隊列裏面。執行這個call的時候,自然會去走到這個call的run方法。
private int maxRequests = 64; private int maxRequestsPerHost = 5; synchronized void enqueue(AsyncCall call) { //如果正在執行的請求小於設定值即64,並且請求同一個主機的request小於設定值即5 if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { //添加到執行隊列,開始執行請求 runningAsyncCalls.add(call); //獲得當前線程池,沒有則創建一個 executorService().execute(call); } else { //添加到等待隊列中 readyAsyncCalls.add(call); } }
- 那麼咱們看下AsyncCall.java這個類,而AsyncCall.java又繼承自NamedRunnable.java咱們就一起看下他們的源碼
public abstract class NamedRunnable implements Runnable { protected final String name; public NamedRunnable(String format, Object... args) { this.name = Util.format(format, args); } @Override public final void run() { String oldName = Thread.currentThread().getName(); Thread.currentThread().setName(name); try { execute(); } finally { Thread.currentThread().setName(oldName); } } protected abstract void execute(); } final class AsyncCall extends NamedRunnable { private final Callback 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 void execute() { boolean signalledCallback = false; try { 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) { 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); } } }
- 上面看到NamedRunnable的構造方法設置了name在的run方法裏面設定爲當前線程的name,而NamedRunnable的run方法裏面調用了它自己的抽象方法execute,由此可見NamedRunnable的作用就是設置了線程的name,然後回調子類的execute方法,那麼我們來看下AsyncCall的execute方法。貌似好像又回到了之前同步的getResponseWithInterceptorChain()裏面,根據返回的response來這隻callback回調。
07.主要流程圖
- 根據上面分析,大概流程圖如下所示