發起一個簡單的Okhttp請求:
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request
.Builder()
.url("https://www.baidu.com")
.build();
okhttp3.Call call = okHttpClient.newCall(request);
////同步請求
//call.execute();
//異步請求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("tag", "請求失敗");
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) {
Log.e("tag", "請求成功");
}
});
構建Okhttp的幾個基礎類:
Request:請求方法、請求頭、參數、請求體等基礎參數的封裝類
OkhttpClient:用於構建Call請求的工廠類,用於配置請求如超時時間、緩存、https證書驗證、攔截器等,內部還封裝了用於分發請求的Dispatcher類、Socket工廠類、Socket連接池等。
Call:請求的發起、取消、結果返回、狀態回調,是Okhttp請求的控制類
Okhttp請求執行的基本流程如下圖:
同步請求
Call的實現類RealCall調用execute()發起同步請求,接着調用getResponseWithInterceptorChain()方法獲取同步響應結果,此方法的具體實現後面統一分析
@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);
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
異步請求
RealCall調用enqueue()方法發起異步請求,實際上是通過其內部保存的OkhttpClient引用,獲取到請求分發器Dispacher,創建RealCall的內部類AsyncCall對象(其實是一個Runnable對象),添加到請求隊列中
class 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));
}
.......
}
接下來看一下Dispatcher中的實現,它內部封裝了線程池、待執行的、執行中的同步/異步請求隊列以及請求數量的限制條件
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
private @Nullable ExecutorService executorService;
//待執行的異步請求隊列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在執行的異步請求
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在執行的同步請求
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
//創建線程池
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;
}
//添加請求到待執行隊列
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();
}
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();
//最大支持同時64個異步請求
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
//同一host下最大支持同時5個異步請求
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
//統計同一host下同時請求個數
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;
}
......
}
接着看異步請求的執行流程,上述代碼第30行Dispatcher調用enqueue()方法將AsyncCall添加到待執行的請求隊列,第41行調用promoteAndExecute()真正將請求添加到線程池執行。
從方法內部可以看到Okhttp對於併發數量是有限制的,最大同時執行的請求數量爲64個,同一host下最多可以同時執行5個請求。
最後遍歷可執行的請求,邏輯從Dispatcher類中切換到AsyncCall中,AsyncCall本身又是一個Runnable,它的最終執行邏輯一定是在run()方法中實現的,跟蹤代碼可以看到它的邏輯切換流程executeOn(executorService) --> 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);
}
} finally {
client.dispatcher().finished(this);
}
}
這裏的代碼和同步請求RealCall中execute()非常相似,同樣是調用getResponseWithInterceptorChain()獲取響應結果,只不過異步請求的Response回調執行在子線程中。
攔截器(Interceptor)
無論是同步請求還是異步請求都是調用getResponseWithInterceptorChain()獲取響應結果,方法命名很直觀,通過攔截器鏈來獲取響應。
Response getResponseWithInterceptorChain() throws IOException {
//將各種攔截器添加到集合
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()));
//添加連接攔截器,給當前請求創建或者從緩存裏獲取一個可用連接(建立socket連接)
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//添加自定義的網絡攔截器
interceptors.addAll(client.networkInterceptors());
}
//添加請求服務攔截器,真正發起請求通過io流獲取響應信息(通過socket連接發送數據以及接受響應)
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 {
/*
* 開始攔截器鏈的執行,根據index獲取攔截器執行intercept()方法,intercept()內部通過自增的index參數構建新的攔截器鏈節點,
* 通過其調用proceed()又開啓下一個攔截器的處理,這樣就構成了一個完整的循環遍歷執行攔截器的過程
*/
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);
}
}
}
}
方法內部定義了Interceptor集合依次將以下攔截器添加到集合中:
自定義Interceptor:我們自己實現的攔截器,比如我們有時候想要在請求前統一添加公共參數或者添加請求、響應的日誌都可以自定義攔截器來實現;
RetryAndFollowUpInterceptor:實現了失敗重試和重定向的一些策略;
BridgeInterceptor:處理我們添加的請求頭以及添加一些默認請求頭信息如gzip透明壓縮等;
CacheInterceptor:處理緩存策略的一些邏輯;
ConnectInterceptor:創建Socket和服務器進行連接,維護Socket連接池;有興趣的朋友可以跟以下這個攔截器的代碼它最終創建Socket連接實在RealConnection類中實現的
自定義NetworkInterceptor:通常用於監聽Socket連接內容,如Facebook出品的Stetho,可以很方便的讓我們通過瀏覽器調試接口
CallServerInterceptor:向Socket連接發送請求數據並且獲取響應數據,它底層用Okio庫替代了Java原生的io流操作。
getResponseWithInterceptorChain()方法內部創建了一個重要的對象RealInterceptorChain,它的構造函數會傳入一個index,這個index正是下一個所要執行的攔截器在集合中的下標,process()方法每調用依次index都會隨之遞增,而每個Interceptor的intercept()方法中又會調用RealInterceptorChain的process()方法,這樣就達到了遍歷執行Intercepter的目的
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
......
// 執行下一個攔截器的代碼
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
......
return response;
}
如上圖所示,攔截器鏈在遍歷執行的過程中,依次對Request進行攔截處理最後獲取到響應後又沿着相反的方向將Response返回,在返回的過程中攔截器又可以逐層最Response進行處理,將最終結果返回給Call對象,這樣就完成一個完整的Okhttp請求流程。