主要參考文章:
1.Okhttp的基本使用
2.Okhttp主流程源碼分析
Okhttp 3.12.0 使用例子
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.get()//默認(rèn)就是GET請(qǐng)求襟齿,可以不寫
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("ziq", "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("ziq", "onResponse: " + response.body().string());
}
});
1、初始化
建造者模式瓤介,public OkHttpClient() { this(new Builder());} 初始化了一些配置信息:支持協(xié)議灭衷、任務(wù)分發(fā)器(其內(nèi)部包含一個(gè)線程池辆亏,執(zhí)行異步請(qǐng)求)、連接池(其內(nèi)部包含一個(gè)線程池晋涣,維護(hù)connection)、連接/讀/寫超時(shí)時(shí)長(zhǎng)等信息沉桌。
public Builder() {
dispatcher = new Dispatcher();//任務(wù)調(diào)度器
protocols = DEFAULT_PROTOCOLS;//支持的協(xié)議 Protocol.HTTP_2, Protocol.HTTP_1_1
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;//根據(jù)地址與證書 進(jìn)行校驗(yàn)X509Certificate
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;//身份驗(yàn)證
authenticator = Authenticator.NONE;//身份驗(yàn)證
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;
}
下面列出 Dispatcher 的主要分析部分
//Dispatcher.java
public final class Dispatcher {
private int maxRequests = 64;//最大請(qǐng)求數(shù)量
private int maxRequestsPerHost = 5;//每臺(tái)主機(jī)最大的請(qǐng)求數(shù)量
private @Nullable Runnable idleCallback;
private @Nullable ExecutorService executorService;//線程池
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//等待隊(duì)列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//異步運(yùn)行中隊(duì)列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//同步運(yùn)行中隊(duì)列
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
谢鹊。。留凭。
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);//添加到異步運(yùn)行隊(duì)列中
}
promoteAndExecute();//將 readyAsyncCalls中的call 添加到 runningAsyncCalls并運(yùn)行
}
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();
//正在運(yùn)行的任務(wù)數(shù)是否大于 64
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
//對(duì)應(yīng)主機(jī) 的 正在運(yùn)行的任務(wù)數(shù)是否大于 5
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
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;
}
佃扼。。蔼夜。
}
2兼耀、生成call 并 請(qǐng)求
//OkHttpClient.java
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
//RealCall.java
new RealCall(client, originalRequest, forWebSocket);
@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));
}
那么從dispatcher的代碼中可知道,call直接加入到 readyAsyncCalls隊(duì)列中求冷,然后 在promoteAndExecute方法中判斷是否 可以執(zhí)行 readyAsyncCalls中的任務(wù)瘤运,如果可以則 把任務(wù)加入到runningAsyncCalls ,并 到線程池中執(zhí)行匠题。
3拯坟、執(zhí)行call
asyncCall.executeOn(executorService());
AsyncCall extends NamedRunnable implements Runnable
,所以運(yùn)行run() ->execute() ;
final class AsyncCall extends NamedRunnable {
韭山。郁季。。
@Override protected void execute() {
boolean signalledCallback = false;
timeout.enter();
try {
//1钱磅、進(jìn)過(guò)一系列攔截器后梦裂,返回結(jié)果
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) {
e = timeoutExit(e);
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//2、結(jié)束當(dāng)前call,運(yùn)行未執(zhí)行且符合條件的call
client.dispatcher().finished(this);
}
}
}
4续搀、Interceptor攔截器
到了這里塞琼,到達(dá)了okhttp最核心的部分, Interceptor禁舷,采用了責(zé)任鏈的設(shè)計(jì)模式
4.1client.dispatcher().finished(this)彪杉;
//Dispatcher.java
private <T> void finished(Deque<T> calls, T call) {
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}
可以看到毅往,移除call后,又回到 一開始 的promoteAndExecute() 方法派近,去把readyAsyncCalls中的call 拿出來(lái)運(yùn)行攀唯。
4.2 責(zé)任鏈
Response response = getResponseWithInterceptorChain();進(jìn)過(guò)一系列攔截器后,返回結(jié)果
//RealCall.java
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
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, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
添加的各Interceptor渴丸,分別負(fù)責(zé)功能:
client.interceptors() 用戶自定義的Interceptor侯嘀,能攔截到所有的請(qǐng)求
RetryAndFollowUpInterceptor 負(fù)責(zé)失敗重連和重定向相關(guān)
BridgeInterceptor 負(fù)責(zé)配置請(qǐng)求的頭信息,比如Keep-Alive谱轨、gzip戒幔、Cookie等可以優(yōu)化請(qǐng)求
CacheInterceptor 負(fù)責(zé)緩存管理,使用DiskLruCache做本地緩存土童,CacheStrategy決定緩存策略
ConnectInterceptor 開始與目標(biāo)服務(wù)器建立連接诗茎,獲得RealConnection
client.networkInterceptors() 用戶自定義的Interceptor,僅在生產(chǎn)網(wǎng)絡(luò)請(qǐng)求時(shí)生效
CallServerInterceptor 實(shí)際網(wǎng)絡(luò)請(qǐng)求的地方献汗。
遞歸實(shí)現(xiàn):
1敢订、RealInterceptorChain.proceed(...) 為開頭敦腔,會(huì)生成 下一步的RealInterceptorChain next1疟赊,與當(dāng)前的RealInterceptorChain參數(shù)一樣,區(qū)別是index 加1
了,所以會(huì)調(diào)用 下一級(jí) 攔截器的interceptor1.intercept(next)
2湘捎、interceptor1.intercept(next)調(diào)用 下一個(gè)鏈 next1.proceed(...)方法
3尿招、next1.proceed(...)調(diào)用下一個(gè)interceptor2.intercept(next) 形成 遞歸
4矾柜、最后的攔截器是 CallServerInterceptor,返回response泊业,然后一級(jí)一級(jí)返回response把沼。
//RealInterceptorChain.java
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,RealConnection connection)throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
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 (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
//1、生成 下一步的RealInterceptorChain吁伺,與當(dāng)前的RealInterceptorChain參數(shù)一樣饮睬,區(qū)別是index 加1 了
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
//2、Interceptor interceptor內(nèi)會(huì)調(diào)用 next.proceed(...) 又回到這里的第一步篮奄,再生成一個(gè)chain 形成遞歸
Response response = interceptor.intercept(next);
//結(jié)束遞歸
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
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;
}
各個(gè)攔截器部分細(xì)節(jié)描述:
攔截器 | 描述 |
---|---|
RetryAndFollowUpInterceptor | 生成 StreamAllocation 實(shí)例捆愁,后面的攔截器使用 |
BridgeInterceptor | 添加header參數(shù) |
CacheInterceptor | 默認(rèn)是沒(méi)有緩存的,全都是直接網(wǎng)絡(luò)請(qǐng)求窟却。 |
ConnectInterceptor | 利用上面 的StreamAllocation 建立 HttpCodec昼丑、RealConnection實(shí)例從connectionPool 尋找是否有RealConnection,有就直接賦值給StreamAllocation 中的connection 找不到就result = new RealConnection(connectionPool, selectedRoute);新建夸赫,賦值給StreamAllocation并且緩存到connectionPool |
CallServerInterceptor | 使用前面其他攔截器生成的 StreamAllocation 菩帝, RealConnection, HttpCodec;而HttpCodec 中使用okio 通過(guò) Socket 傳輸數(shù)據(jù)呼奢,網(wǎng)絡(luò)請(qǐng)求宜雀。 |