前言
相信大家想仔細認真的看下源碼憔儿,然后去網(wǎng)上找資料都會有這樣的兩個感覺
- 版本不一致,導致和博主分析的有偏差
- 突然就跳轉到某個關鍵類镰禾,根本不知道是從哪里進去的
反正阿簡在看源碼找資料的時候就是這樣皿曲,說著說著快流了淚...
那阿簡今天來和大家一起慢慢分析一下okhttp攔截器源碼
先上總的框架圖
源碼分析準備
- app的build.gradle引入okhttp相關包
implementation 'com.squareup.okhttp3:okhttp:3.14.4'
- 創(chuàng)建一個簡單的activity,寫一個簡單的GET請求的okhttp異步方法
private void okhttpTest() {
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(TestInterceptor);
final Request request = new Request.Builder()
.url(url)
.get()//默認就是GET請求吴侦,可以不寫
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
}
然后開始我們的源碼分析~
首先屋休,我們創(chuàng)建了一個OkHttpClient,點進去看它的構造方法备韧,初始化了一個叫做Builder的靜態(tài)內部類,我們看看初始化了哪些參數(shù)(部分參數(shù)介紹請看注釋)
public Builder() {
//任務調度器
dispatcher = new Dispatcher();
//支持的協(xié)議
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是一個連接池對象劫樟,它可以用來管理連接對象,從它的構造方法中可以看到連接池的默認空閑連接數(shù)為5個织堂,keepAlive時間為5分鐘叠艳。
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易阳,其他都是一些一看命名就大致知道的成員變量附较,那我們來看下這個任務調度器包含什么
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;
/** 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<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
可以看到Dispatcher這個類中包含了兩個異步隊列,一個同步隊列用來保存請求潦俺,該文章主要從異步請求分析拒课,所以大家可以記一下這兩個異步請求的成員變量名稱徐勃,后面會用到readyAsyncCalls ,runningAsyncCalls
接著我們通過建造者模式創(chuàng)建了一個Request請求:
final Request request = new Request.Builder()
.url(url)
.get()//默認就是GET請求早像,可以不寫
.build();
可以看到Request里面就是包含一個完整的請求報文的幾個成員變量僻肖,對這部門計算機網(wǎng)絡有疑惑的小伙伴可以參考阿簡的這篇文章喲:網(wǎng)絡基本知識-http
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Map<Class<?>, Object> tags;
緊接著,我們通過okhttpClient去new了一個請求(call)卢鹦,newCall點進去
Call call = okHttpClient.newCall(request);
可以看到最后是調用到了一個叫RealCall類的一個靜態(tài)方法newRealCall臀脏,該方法創(chuàng)建了一個realCall的成員變量,傳入了OkHttpClient 對象冀自,同時創(chuàng)建了一個叫Transmitter的對象揉稚,這個類是干嘛的后面會提到(官方注釋是:OkHttp的應用層和網(wǎng)絡層之間的橋梁)
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.transmitter = new Transmitter(client, call);
return call;
}
然后開始我們的異步請求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
點進去,可以看到Call只有一個實現(xiàn)類凡纳,就是我們剛才的那個RealCall窃植,
@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));
}
可以看到這里transmitter干了一件事callStart()
然后通過Okhttp的那個成員變量dispatcher(任務調度器)調用了異步方法enqueue(AsyncCall call),傳入了我們的CallBack回調監(jiān)聽(觀察者模式喔)
然后最最最重要的來啦
我們看RealCall里面的這個內部類AsyncCall荐糜,繼承了NamedRunnable巷怜,NamedRunnable又實現(xiàn)了Runnable 接口,那必然要實現(xiàn)run方法暴氏,run方法里面又調用了execute
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();
大家記住這個AsyncCall延塑,后面會調用到這里的關鍵代碼
回到剛才 client.dispatcher().enqueue這里,可以看到Dispatcher中的enqueue方法答渔,我們的請求放入了readyAsyncCalls這個異步隊列
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();
}
進入promoteAndExecute()方法关带,這個方法很重要哦,可以看到兩個判斷條件
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
如果正在執(zhí)行的異步請求數(shù)量大于最大的請求數(shù)量(maxRequests 默認等于64)的話
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity
每個主機最大請求數(shù)沼撕,默認為5
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
//創(chuàng)建一個臨時變量List用作儲存異步請求
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();
//循環(huán)中把請求分別放入臨時變量和readyAsyncCalls中
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
//遍歷該臨時變量宋雏,執(zhí)行executeOn
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
我們看到遍歷的 asyncCall.executeOn(executorService())這行代碼,然后回到了RealCall的內部類AsyncCall的executeOn方法务豺,然后傳入了ThreadPoolExecutor線程池對象
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!
}
}
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
執(zhí)行了 executorService.execute(this)磨总,傳入了this,this是什么,是不是就是我們剛才的那個實現(xiàn)Runable的實現(xiàn)類AsyncCall本身笼沥,其實這里已經(jīng)很清楚了蚪燕,傳入Runable到線程池,線程池肯定會多態(tài)重寫執(zhí)行run方法奔浅,run方法又調用了execute
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
Response response = getResponseWithInterceptorChain();
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);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
client.dispatcher().finished(this);
}
}
}
然后攔截器來了馆纳,大家進入RealCall的
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
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);
}
}
}
可以看到interceptors 這個list中放入了很多攔截器,最新放入的是我們的應用攔截器OkHttpClient.Builder().addInterceptor(TestInterceptor)
這些攔截器的作用我后面會說明
然后就開始了我們的攔截器責任鏈的代碼了(原理也是非常的簡單)
這里創(chuàng)建了一個RealInterceptorChain對象汹桦,然后開始執(zhí)行proceed傳入原始的請求originalRequest
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
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.exchange != null && !this.exchange.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.exchange != 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, transmitter, exchange,
index + 1, request, call, 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 (exchange != 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;
}
每次傳入的index+1取集合中的下一個攔截器執(zhí)行intercept鲁驶,然后intercept中又執(zhí)行proceed進行下一次的攔截執(zhí)行
是不是非常非常的簡單!舞骆!
然后開始收尾钥弯,execute中最后finall執(zhí)行了 client.dispatcher().finished(this);
void finished(AsyncCall call) {
call.callsPerHost().decrementAndGet();
finished(runningAsyncCalls, call);
}
可以看到finished了promoteAndExecute()中放入runningAsyncCalls的對象壹罚,然后結束了
大致就分析到這里
開始分析下剛才說的幾個攔截器
RetryAndFollowUpInterceptor,用來實現(xiàn)連接失敗的重試和重定向寿羞。
BridgeInterceptor,用來修改請求和響應的 header 信息赂蠢。
CacheInterceptor绪穆,用來實現(xiàn)響應緩存。比如獲取到的 Response 帶有 Date虱岂,Expires,Last-Modified第岖,Etag 等 header,表示該 Response 可以緩存一定的時間蔑滓,下次請求就可以不需要發(fā)往服務端,直接拿緩存的键袱。
ConnectInterceptor燎窘,用來打開到服務端的連接。其實是調用了 StreamAllocation 的newStream 方法來打開連接的褐健。建聯(lián)的 TCP 握手,TLS 握手都發(fā)生該階段蚜迅。過了這個階段,和服務端的 socket 連接打通俊抵。
CallServerInterceptor谁不,用來發(fā)起請求并且得到響應。上一個階段已經(jīng)握手成功拍谐,HttpStream 流已經(jīng)打開馏段,所以這個階段把 Request 的請求信息傳入流中轩拨,并且從流中讀取數(shù)據(jù)封裝成 Response 返回院喜。
攔截器分類
- 應用攔截器喷舀,就是我們addInterceptor添加的攔截器
- 網(wǎng)絡攔截器 addNetworkInterceptor添加的攔截器
兩個的特點分別是:
應用攔截器
1.不需要關心是否重定向或者失敗重連
2.應用攔截器只會調用一次砍濒,即使數(shù)據(jù)來源于緩存
3.自定義的應用攔截器是第一個開始執(zhí)行的攔截器,所以這句話的意思就是樊卓,應用攔截器可以決定是否執(zhí)行其他的攔截器(如果不想繼續(xù)往下傳遞請求杠河,那么就不調用Chain.proceed()),通過Chain.proceed()
看getResponseWithInterceptorChain()方法結合責任鏈券敌,可以很好的理解這幾個特點
網(wǎng)絡攔截器
1.允許像重定向和重試一樣操作中間響應。
2.網(wǎng)絡發(fā)生短路時不調用緩存響應叹坦。
3.在數(shù)據(jù)被傳遞到網(wǎng)絡時觀察數(shù)據(jù)卑雁。
4.有權獲得裝載請求的連接。
以下關于官網(wǎng)介紹的這張圖區(qū)分應用攔截器和網(wǎng)絡攔截器序厉,通過getResponseWithInterceptorChain方法可以很好的理解,最新執(zhí)行的是應用攔截器