日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )

發(fā)布時(shí)間:2025/6/17 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 ) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

OkHttp 系列文章目錄

【OkHttp】OkHttp 簡(jiǎn)介 ( OkHttp 框架特性 | Http 版本簡(jiǎn)介 )
【OkHttp】Android 項(xiàng)目導(dǎo)入 OkHttp ( 配置依賴 | 配置 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 類型對(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ù)路基 ;

Response getResponseWithInterceptorChain() throws IOException {// Build a full stack of interceptors.List<Interceptor> interceptors = new ArrayList<>();interceptors.addAll(client.interceptors());interceptors.add(new RetryAndFollowUpInterceptor(client));// 處理網(wǎng)橋的鏈接器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, transmitter, null, 0,originalRequest, this, client.connectTimeoutMillis(),client.readTimeoutMillis(), client.writeTimeoutMillis());boolean calledNoMoreExchanges = false;try {Response response = chain.proceed(originalRequest);if (transmitter.isCanceled()) {closeQuietly(response);throw new IOException("Canceled");}return response;} catch (IOException e) {calledNoMoreExchanges = true;throw transmitter.noMoreExchanges(e);} finally {if (!calledNoMoreExchanges) {transmitter.noMoreExchanges(null);}}}

( 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 Runnable

2、Dispatcher 調(diào)度器 promoteAndExecute 方法分析


分析 promoteAndExecute 方法 : 將符合條件的調(diào)用從 readyAsyncCalls 提升為 runningAsyncCalls , 并且在線程池中調(diào)用它們 ; 這些操作必須同步調(diào)用 , 因?yàn)閳?zhí)行這些調(diào)用需要調(diào)用用戶代碼 ;

最終的異步請(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)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。