【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )
OkHttp 系列文章目錄
【OkHttp】OkHttp 簡(jiǎn)介 ( OkHttp 框架特性 | Http 版本簡(jiǎn)介 )
【OkHttp】Android 項(xiàng)目導(dǎo)入 OkHttp ( 配置依賴(lài) | 配置 networkSecurityConfig | 配置 ViewBinding | 代碼示例 )
【OkHttp】OkHttp Get 和 Post 請(qǐng)求 ( 同步 Get 請(qǐng)求 | 異步 Get 請(qǐng)求 | 同步 Post 請(qǐng)求 | 異步 Post 請(qǐng)求 )
【OkHttp】OkHttp 上傳圖片 ( 獲取 SD 卡動(dòng)態(tài)權(quán)限 | 跳轉(zhuǎn)到相冊(cè)界面選擇圖片 | 使用 OkHttp 上傳圖片文件 )
【OkHttp】OkHttp 源碼分析 ( 網(wǎng)絡(luò)框架封裝 | OkHttp 4 遷移 | OkHttp 建造者模式 )
【OkHttp】OkHttp 源碼分析 ( OkHttpClient.Builder 構(gòu)造器源碼分析 )
【OkHttp】OkHttp 源碼分析 ( 同步 / 異步 Request 請(qǐng)求執(zhí)行原理分析 )
文章目錄
- OkHttp 系列文章目錄
- 一、分析 OkHttp 執(zhí)行原理
- 1、創(chuàng)建 OkHttpClient
- 2、創(chuàng)建 Request
- 3、獲取 RealCall
- 4、通過(guò) RealCall 發(fā)送 同步 / 異步 Request 請(qǐng)求
- ( 1 ) 、同步 Request 請(qǐng)求
- ( 2 ) 、異步 Request 請(qǐng)求
- 二、OkHttp 異步 Request 請(qǐng)求源碼分析
- 1、Dispatcher 調(diào)度器 enqueue 方法分析
- 2、Dispatcher 調(diào)度器 promoteAndExecute 方法分析
- 3、AsyncCall 的 executeOn 方法分析
- 三、OkHttp 請(qǐng)求時(shí)序圖參考
- 四、博客資源
一、分析 OkHttp 執(zhí)行原理
以 OkHttp 同步 / 異步 Get 請(qǐng)求為例 , 分析底層的運(yùn)行細(xì)節(jié) ;
/*** OkHttp 異步 Get 請(qǐng)求*/private void httpAsynchronousGet() {// 初始化 OkHttp OkHttpClient mOkHttpClient = new OkHttpClient();// Request 中封裝了請(qǐng)求相關(guān)信息Request request = new Request.Builder().url("https://www.baidu.com") // 設(shè)置請(qǐng)求地址.get() // 使用 Get 方法.build();// 異步 Get 請(qǐng)求mOkHttpClient.newCall(request).enqueue(new Callback(){@Overridepublic void onFailure(Call call, IOException e) {// 請(qǐng)求失敗的情況}@Overridepublic void onResponse(Call call, Response response) throws IOException {// 請(qǐng)求成功 , 獲取String result = response.body().string();Log.i(TAG, "result : " + result);runOnUiThread(new Runnable() {@Overridepublic void run() {// 主線程中執(zhí)行相關(guān)代碼}});}});}1、創(chuàng)建 OkHttpClient
創(chuàng)建 OkHttpClient : 調(diào)用者調(diào)用 OkHttpClient 構(gòu)造函數(shù) , 創(chuàng)建 OkHttpClient , 然后返回給調(diào)用者 ;
OkHttpClient mOkHttpClient = new OkHttpClient();OkHttpClient 構(gòu)造函數(shù)中 , 實(shí)際上創(chuàng)建了自身的創(chuàng)建者 ;
public OkHttpClient() {this(new Builder());}上述創(chuàng)建者構(gòu)造函數(shù)調(diào)用的是無(wú)參構(gòu)造函數(shù) , 也就是默認(rèn)設(shè)置了一系列參數(shù) , 如下 :
public static final class Builder {public Builder() {dispatcher = new Dispatcher();protocols = DEFAULT_PROTOCOLS;connectionSpecs = DEFAULT_CONNECTION_SPECS;eventListenerFactory = EventListener.factory(EventListener.NONE);proxySelector = ProxySelector.getDefault();if (proxySelector == null) {proxySelector = new NullProxySelector();}cookieJar = CookieJar.NO_COOKIES;socketFactory = SocketFactory.getDefault();hostnameVerifier = OkHostnameVerifier.INSTANCE;certificatePinner = CertificatePinner.DEFAULT;proxyAuthenticator = Authenticator.NONE;authenticator = Authenticator.NONE;connectionPool = new ConnectionPool();dns = Dns.SYSTEM;followSslRedirects = true;followRedirects = true;retryOnConnectionFailure = true;callTimeout = 0;connectTimeout = 10_000;readTimeout = 10_000;writeTimeout = 10_000;pingInterval = 0;}}2、創(chuàng)建 Request
創(chuàng)建 Request 時(shí) , 使用 Request 的創(chuàng)建者 Request.Builder 創(chuàng)建該 Request 對(duì)象 ;
先調(diào)用 Request.Builder 的構(gòu)造函數(shù) , 創(chuàng)建 Request.Builder 對(duì)象 , 然后調(diào)用 Request.Builder 的 build 方法 , 創(chuàng)建 Request 對(duì)象 ;
// Request 中封裝了請(qǐng)求相關(guān)信息 Request request = new Request.Builder().url("https://www.baidu.com") // 設(shè)置請(qǐng)求地址.get() // 使用 Get 方法.build();3、獲取 RealCall
調(diào)用 OkHttpClient 對(duì)象的 newCall 方法 , 發(fā)起新的請(qǐng)求調(diào)用 , 返回 111 個(gè) RealCall 類(lèi)型對(duì)象 ;
mOkHttpClient.newCall(request)在 OkHttpClient 的 newCall 方法中 , 創(chuàng)建了 RealCall , 并返回給了調(diào)用者 ;
/*** Prepares the {@code request} to be executed at some point in the future.*/@Override public Call newCall(Request request) {return RealCall.newRealCall(this, request, false /* for web socket */);}RealCall 實(shí)現(xiàn)了 Call 接口 ;
final class RealCall implements Call {final OkHttpClient client; }Call 接口提供的功能 : execute 是同步請(qǐng)求 , enqueue 是異步請(qǐng)求 ;
public interface Call extends Cloneable {Request request();Response execute() throws IOException;void enqueue(Callback responseCallback);void cancel();boolean isExecuted();boolean isCanceled();Timeout timeout();Call clone();interface Factory {Call newCall(Request request);} }4、通過(guò) RealCall 發(fā)送 同步 / 異步 Request 請(qǐng)求
RealCall 實(shí)現(xiàn)了上述 Call 接口的各項(xiàng)功能 , 主要關(guān)注其實(shí)現(xiàn) Call 接口的 execute 同步請(qǐng)求方法 , enqueue 異步請(qǐng)求方法 ;
final class RealCall implements Call {@Override public Response execute() throws IOException {synchronized (this) {if (executed) throw new IllegalStateException("Already Executed");executed = true;}transmitter.timeoutEnter();transmitter.callStart();try {client.dispatcher().executed(this);// 返回一個(gè)責(zé)任鏈 return getResponseWithInterceptorChain();} finally {client.dispatcher().finished(this);}}@Override public void enqueue(Callback responseCallback) {synchronized (this) {if (executed) throw new IllegalStateException("Already Executed");executed = true;}transmitter.callStart();client.dispatcher().enqueue(new AsyncCall(responseCallback));} }( 1 ) 、同步 Request 請(qǐng)求
同步請(qǐng)求方法 , 返回一個(gè)責(zé)任鏈 , 在該方法中可以清楚的看到 OkHttp 的 Get 請(qǐng)求具體做了哪些步驟 ;
在該方法中通過(guò)添加不同功能的攔截器 , 實(shí)現(xiàn)相關(guān)業(yè)務(wù)路基 ;
( 2 ) 、異步 Request 請(qǐng)求
在 RealCall 的 enqueue 異步請(qǐng)求方法中 , 最終調(diào)用的還是 OkHttpClient 的 dispatcher 進(jìn)行調(diào)度 ;
在上一篇博客 【OkHttp】OkHttp 源碼分析 ( OkHttpClient.Builder 構(gòu)造器源碼分析 ) 已經(jīng)提到過(guò) OkHttpClient 的 Dispatcher dispatcher 成員 , 是 Get / Post 方法的請(qǐng)求線程調(diào)度器 ;
final class RealCall implements Call {final OkHttpClient client;@Override public void enqueue(Callback responseCallback) {synchronized (this) {if (executed) throw new IllegalStateException("Already Executed");executed = true;}transmitter.callStart();client.dispatcher().enqueue(new AsyncCall(responseCallback));} }二、OkHttp 異步 Request 請(qǐng)求源碼分析
異步 Request 請(qǐng)求涉及到線程調(diào)度 , 比較復(fù)雜 ;
OKHttpClient 調(diào)用 newCall 獲取 RealCall , 然后調(diào)用 RealCall 的 enqueue 方法進(jìn)行異步 Get/Post 請(qǐng)求 , 在該方法中最終調(diào)用 OKHttpClient 對(duì)象中的 Dispatcher dispatcher 線程調(diào)度器 的 enqueue 方法 , 進(jìn)行異步請(qǐng)求 ;
1、Dispatcher 調(diào)度器 enqueue 方法分析
在 Dispatcher 的 enqueue 方法中 , 調(diào)用了 findExistingCallWithHost 方法獲取 AsyncCall , 然后在方法最后調(diào)用了 promoteAndExecute 進(jìn)行后續(xù)執(zhí)行異步任務(wù)操作 ;
/*** Policy on when async requests are executed.** <p>Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your* own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number* of calls concurrently.*/ public final class Dispatcher {void enqueue(AsyncCall call) {synchronized (this) {readyAsyncCalls.add(call);// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to// the same host.if (!call.get().forWebSocket) {AsyncCall existingCall = findExistingCallWithHost(call.host());if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);}}promoteAndExecute();}@Nullable private AsyncCall findExistingCallWithHost(String host) {for (AsyncCall existingCall : runningAsyncCalls) {if (existingCall.host().equals(host)) return existingCall;}for (AsyncCall existingCall : readyAsyncCalls) {if (existingCall.host().equals(host)) return existingCall;}return null;} }AsyncCall 繼承了 NamedRunnable , NamedRunnable 實(shí)現(xiàn)了 Runnable 接口 , AsyncCall 本質(zhì)是 Runnable ;
final class AsyncCall extends NamedRunnable public abstract class NamedRunnable implements Runnable2、Dispatcher 調(diào)度器 promoteAndExecute 方法分析
分析 promoteAndExecute 方法 : 將符合條件的調(diào)用從 readyAsyncCalls 提升為 runningAsyncCalls , 并且在線程池中調(diào)用它們 ; 這些操作必須同步調(diào)用 , 因?yàn)閳?zhí)行這些調(diào)用需要調(diào)用用戶(hù)代碼 ;
最終的異步請(qǐng)求執(zhí)行調(diào)用的是 AsyncCall 的 executeOn 方法 ;
AsyncCall asyncCall = executableCalls.get(i);asyncCall.executeOn(executorService());Dispatcher | promoteAndExecute 方法源碼 :
/*** Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs* them on the executor service. Must not be called with synchronization because executing calls* can call into user code.** @return true if the dispatcher is currently running calls.*/private boolean promoteAndExecute() {assert (!Thread.holdsLock(this));List<AsyncCall> executableCalls = new ArrayList<>();boolean isRunning;synchronized (this) {for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {AsyncCall asyncCall = i.next();if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.i.remove();asyncCall.callsPerHost().incrementAndGet();executableCalls.add(asyncCall);runningAsyncCalls.add(asyncCall);}isRunning = runningCallsCount() > 0;}for (int i = 0, size = executableCalls.size(); i < size; i++) {AsyncCall asyncCall = executableCalls.get(i);asyncCall.executeOn(executorService());}return isRunning;}3、AsyncCall 的 executeOn 方法分析
AsyncCall 的 executeOn 方法中 , 主要使用了 傳入的 ExecutorService executorService 線程池 , 執(zhí)行異步請(qǐng)求任務(wù) ;
RealCall $ AsyncCall | executeOn 方法代碼 :
final class RealCall implements Call {final class AsyncCall extends NamedRunnable {/*** Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up* if the executor has been shut down by reporting the call as failed.*/void executeOn(ExecutorService executorService) {assert (!Thread.holdsLock(client.dispatcher()));boolean success = false;try {executorService.execute(this);success = true;} catch (RejectedExecutionException e) {InterruptedIOException ioException = new InterruptedIOException("executor rejected");ioException.initCause(e);transmitter.noMoreExchanges(ioException);responseCallback.onFailure(RealCall.this, ioException);} finally {if (!success) {client.dispatcher().finished(this); // This call is no longer running!}}}} }三、OkHttp 請(qǐng)求時(shí)序圖參考
四、博客資源
GitHub : https://github.com/han1202012/OkHttp
總結(jié)
以上是生活随笔為你收集整理的【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【OkHttp】OkHttp 源码分析
- 下一篇: 【Android TV 开发】焦点处理