OkHttp 源碼詳解
OkHttp應該是目前Android平臺上使用最為廣泛的開源網絡庫了,Android 在6.0之后也將內部的HttpUrlConnection的默認實現替換成了OkHttp。
這篇文章的目的,了解okhttp的框架原理,以及責任鏈模式的使用。
1、發送請求
首先看一下,怎么發出一個同步/異步請求。
/**
* 同步發起請求
*
* @throws IOException
*/
private void execute() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("your url").build();
Response syncResponse = client.newCall(request).execute();
}
/**
* 異步發起請求
*
* @throws IOException
*/
private void enqueue() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("your url").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
}
});
}
這一段代碼就是日常使用OkHttp最常見的用法,跟進源碼后,可以得到一張更為詳細的流程圖,通過這張圖來看下內部的邏輯是如何流動的。
其實很簡單,只有幾個核心類,我們一個個來看一下。
- OkHttpClient
- Request 和 Response
- RealCall
OkHttpClient:這個是整個OkHttp的核心管理類,所有的內部邏輯和對象歸OkHttpClient統一來管理,它通過Builder構造器生成,構造參數和類成員很多,這里先不做具體的分析。
Request 和Response:Request是我們發送請求封裝類,內部有url, header , method,body等常見的參數,Response是請求的結果,包含code, message, header,body ;這兩個類的定義是完全符合Http協議所定義的請求內容和響應內容。
RealCall:負責請求的調度(同步的話走當前線程發送請求,異步的話則使用OkHttp內部的線程池進行);同時負責構造內部邏輯責任鏈,并執行責任鏈相關的邏輯,直到獲取結果。雖然OkHttpClient是整個OkHttp的核心管理類,但是真正發出請求并且組織邏輯的是RealCall類,它同時肩負了調度和責任鏈組織的兩大重任,接下來我們來著重分析下RealCall類的邏輯。
大致總結就是,OkHttpClient 和 Request 都是使用了 Builder 設計模式,然后,Request 通過 OkHttpClient 把 同步/異步 請求發送出去.
2、同步/異步
我們跟進源碼,看一下同步/異步的請求原理
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
可以看到最終的請求處理是 dispatcher 來完成的,接下來看下 dispatcher
//最大并發請求書
private int maxRequests = 64;
//每個主機的最大請求數
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** 執行的線程池. Created lazily. */
private 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() {
}
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;
}
Dispatcher 有兩個構造方法,可以自己指定線程池, 如果沒有指定, 則會默認創建默認線程池,可以看到核心數為0,緩存數可以是很大, 比較適合執行大量的耗時比較少的任務。
接著看 enqueue是如何實現的
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
當正在運行的異步請求隊列中的數量小于64, 并且 正在運行的請求主機數小于5,把請求加載到runningAsyncCalls 中并在線程池中執行, 否則就加入到 readyAsyncCalls 進行緩存等待。
上面可以看到傳遞進來的是 AsyncCall 然后 execute 那我們看下 AsyncCall方法
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override protected void execute() {
boolean signalledCallback = false;
try {
//獲取請求報文
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) {
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);
}
}
}
看到 NamedRunnable 實現了 Runnable,AsyncCall 中的 execute 是對網絡請求的具體處理。
Response response = getResponseWithInterceptorChain();
能明顯看出這就是對請求的處理,在看它的具體實現之前先看下 client.dispatcher().finished 的方法實現。
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
// 最后調用這個
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
由于 promoteCalls 是true 我們看下 promoteCalls 的方法實現
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
根據代碼可以明顯看出 , 當一個請求結束了調用 finished 方法,最終到promoteCalls就是把 異步等待隊列中的請求,取出放到 異步執行隊列中。
- 如果異步執行隊列已經是滿的狀態就不加了,return
- 如果 異步等待隊列中 沒有需要執行的網絡請求 也就沒有必要進行下一步了 return
- 上面的兩條都沒遇到,遍歷 異步等待隊列,取出隊首的請求,如果這個請求的 host 符合 (正在執行的網絡請求中 同一個host最多只能是5個)的這個條件, 把 等待隊列的這個請求移除, 加入到 正在執行的隊列中, 線程開始執行。 如果不符合繼續 遍歷操作。
3、interceptors 攔截器
接著看 RealCall 的 getResponseWithInterceptorChain 方法
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()));
//處理 緩存配置 根據條件(存在響應緩存并被設置為不變的或者響應在有效期內)返回緩存響應
//設置請求頭(If-None-Match、If-Modified-Since等) 服務器可能返回304(未修改)
//可配置用戶自己設置的緩存攔截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//連接攔截器 這里才是真正的請求網絡
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//配置okhttpClient 時設置的networkInterceptors
//返回觀察單個網絡請求和響應的不可變攔截器列表。
interceptors.addAll(client.networkInterceptors());
}
//執行流操作(寫出請求體、獲得響應數據) 負責向服務器發送請求數據、從服務器讀取響應數據
//進行http請求報文的封裝與請求報文的解析
interceptors.add(new CallServerInterceptor(forWebSocket));
//創建責任鏈
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
//執行 責任鏈
return chain.proceed(originalRequest);
}
看下 RealInterceptorChain 的實現
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
//創建新的攔截鏈,鏈中的攔截器集合index+1
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
// 執行當前的攔截器
Interceptor interceptor = interceptors.get(index);
// 執行攔截器
Response response = interceptor.intercept(next);
if (httpCodec != 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");
}
return response;
}
根據上面的代碼 我們可以看出,新建了一個RealInterceptorChain 責任鏈 并且 index+1,然后 執行interceptors.get(index); 返回Response。
責任鏈中每個攔截器都會執行chain.proceed()方法之前的代碼,等責任鏈最后一個攔截器執行完畢后會返回最終的響應數據,而chain.proceed() 方法會得到最終的響應數據,這時就會執行每個攔截器的chain.proceed()方法之后的代碼,其實就是對響應數據的一些操作。
結合源碼,可以得到如下結論:
攔截器按照添加順序依次執行
攔截器的執行從RealInterceptorChain.proceed()開始,進入到第一個攔截器的執行邏輯
每個攔截器在執行之前,會將剩余尚未執行的攔截器組成新的RealInterceptorChain
攔截器的邏輯被新的責任鏈調用next.proceed()切分為start、next.proceed、end這三個部分依次執行
next.proceed() 所代表的其實就是剩余所有攔截器的執行邏輯
所有攔截器最終形成一個層層內嵌的嵌套結構
了解了上面攔截器的構造過程,我們再來一個個的分析每個攔截器的功能和作用。
從代碼來看,總共添加了五個攔截器(不包含自定義的攔截器如client.interceptors和client.networkInterceptors,這兩個后面再解釋)。
我們本次分享,只做整體框架的解讀,具體每個攔截器的處理不在此做出贅述。
- retryAndFollowUpInterceptor——失敗和重定向攔截器
- BridgeInterceptor——封裝request和response攔截器
- CacheInterceptor——緩存相關的過濾器,負責讀取緩存直接返回、更新緩存
- ConnectInterceptor——連接服務,負責和服務器建立連接 這里才是真正的請求網絡
- CallServerInterceptor——執行流操作(寫出請求體、獲得響應數據) 負責向服務器發送請求數據、從服務器讀取響應數據 進行http請求報文的封裝與請求報文的解析
4、攔截器demo
個人覺得,okhttp的精髓之一,就是攔截器的理念,針對本理念,寫了個簡單易懂的demo,請笑納。
Interceptor攔截器接口
public interface Interceptor {
String intercept(OkHttpChain chain);
}
Interceptor攔截器鏈
public class OkHttpChain {
private int index = 0;
private List<Interceptor> interceptors;
public OkHttpChain(List<Interceptor> interceptors, int index) {
this.interceptors = interceptors;
this.index = index;
}
public String process() {
if (index >= interceptors.size()) {
return "";
}
OkHttpChain next = new OkHttpChain(interceptors, index + 1);
Interceptor interceptor = interceptors.get(index);
return interceptor.intercept(next);
}
public void add(Interceptor interceptor) {
interceptors.add(interceptor);
}
}
三個Interceptor攔截器
public class AInterceptor implements Interceptor {
@Override
public String intercept(OkHttpChain chain) {
System.out.println("Interceptor_A");
return "A" + chain.process();
}
}
public class BInterceptor implements Interceptor {
@Override
public String intercept(OkHttpChain chain) {
System.out.println("Interceptor_B");
return "_B" + chain.process();
}
}
public class CInterceptor implements Interceptor {
@Override
public String intercept(OkHttpChain chain) {
System.out.println("Interceptor_C");
return "_C" + chain.process();
}
}
執行
public static void main(String[] args) {
List<Interceptor> interceptors = new ArrayList<>();
OkHttpChain chain = new OkHttpChain(interceptors, 0);
interceptors.add(new AInterceptor());
interceptors.add(new BInterceptor());
interceptors.add(new CInterceptor());
String result = chain.process();
System.out.println("result = " + result);
}
執行結果為:
Interceptor_A
Interceptor_B
Interceptor_C
result = A_B_C
參考博客