OkHttp 源碼詳解
OkHttp應(yīng)該是目前Android平臺上使用最為廣泛的開源網(wǎng)絡(luò)庫了处面,Android 在6.0之后也將內(nèi)部的HttpUrlConnection的默認實現(xiàn)替換成了OkHttp玉转。
這篇文章的目的俗慈,了解okhttp的框架原理柑营,以及責(zé)任鏈模式的使用烁竭。
1源梭、發(fā)送請求
首先看一下稳吮,怎么發(fā)出一個同步/異步請求缎谷。
/**
* 同步發(fā)起請求
*
* @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();
}
/**
* 異步發(fā)起請求
*
* @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最常見的用法,跟進源碼后盖高,可以得到一張更為詳細的流程圖慎陵,通過這張圖來看下內(nèi)部的邏輯是如何流動的。
其實很簡單喻奥,只有幾個核心類席纽,我們一個個來看一下。
- OkHttpClient
- Request 和 Response
- RealCall
OkHttpClient:這個是整個OkHttp的核心管理類撞蚕,所有的內(nèi)部邏輯和對象歸OkHttpClient統(tǒng)一來管理润梯,它通過Builder構(gòu)造器生成,構(gòu)造參數(shù)和類成員很多甥厦,這里先不做具體的分析纺铭。
Request 和Response:Request是我們發(fā)送請求封裝類,內(nèi)部有url, header , method刀疙,body等常見的參數(shù)舶赔,Response是請求的結(jié)果,包含code, message, header,body 谦秧;這兩個類的定義是完全符合Http協(xié)議所定義的請求內(nèi)容和響應(yīng)內(nèi)容竟纳。
RealCall:負責(zé)請求的調(diào)度(同步的話走當(dāng)前線程發(fā)送請求,異步的話則使用OkHttp內(nèi)部的線程池進行)疚鲤;同時負責(zé)構(gòu)造內(nèi)部邏輯責(zé)任鏈锥累,并執(zhí)行責(zé)任鏈相關(guān)的邏輯,直到獲取結(jié)果集歇。雖然OkHttpClient是整個OkHttp的核心管理類桶略,但是真正發(fā)出請求并且組織邏輯的是RealCall類,它同時肩負了調(diào)度和責(zé)任鏈組織的兩大重任,接下來我們來著重分析下RealCall類的邏輯际歼。
大致總結(jié)就是惶翻,OkHttpClient 和 Request 都是使用了 Builder 設(shè)計模式,然后蹬挺,Request 通過 OkHttpClient 把 同步/異步 請求發(fā)送出去.
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
//最大并發(fā)請求書
private int maxRequests = 64;
//每個主機的最大請求數(shù)
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** 執(zhí)行的線程池. Created lazily. */
private ExecutorService executorService;
//將要運行的異步請求隊列
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在執(zhí)行的異步請求隊列
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在執(zhí)行的同步請求隊列
/** 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 有兩個構(gòu)造方法,可以自己指定線程池虐秋, 如果沒有指定榕茧, 則會默認創(chuàng)建默認線程池,可以看到核心數(shù)為0客给,緩存數(shù)可以是很大用押, 比較適合執(zhí)行大量的耗時比較少的任務(wù)。
接著看 enqueue是如何實現(xiàn)的
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
當(dāng)正在運行的異步請求隊列中的數(shù)量小于64靶剑, 并且 正在運行的請求主機數(shù)小于5蜻拨,把請求加載到runningAsyncCalls 中并在線程池中執(zhí)行, 否則就加入到 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 實現(xiàn)了 Runnable缎讼,AsyncCall 中的 execute 是對網(wǎng)絡(luò)請求的具體處理。
Response response = getResponseWithInterceptorChain();
能明顯看出這就是對請求的處理坑匠,在看它的具體實現(xiàn)之前先看下 client.dispatcher().finished 的方法實現(xiàn)血崭。
/** 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);
}
// 最后調(diào)用這個
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 的方法實現(xiàn)
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.
}
}
根據(jù)代碼可以明顯看出 , 當(dāng)一個請求結(jié)束了調(diào)用 finished 方法厘灼,最終到promoteCalls就是把 異步等待隊列中的請求夹纫,取出放到 異步執(zhí)行隊列中。
- 如果異步執(zhí)行隊列已經(jīng)是滿的狀態(tài)就不加了设凹,return
- 如果 異步等待隊列中 沒有需要執(zhí)行的網(wǎng)絡(luò)請求 也就沒有必要進行下一步了 return
- 上面的兩條都沒遇到舰讹,遍歷 異步等待隊列,取出隊首的請求闪朱,如果這個請求的 host 符合 (正在執(zhí)行的網(wǎng)絡(luò)請求中 同一個host最多只能是5個)的這個條件月匣, 把 等待隊列的這個請求移除, 加入到 正在執(zhí)行的隊列中监透, 線程開始執(zhí)行桶错。 如果不符合繼續(xù) 遍歷操作。
3胀蛮、interceptors 攔截器
接著看 RealCall 的 getResponseWithInterceptorChain 方法
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//用戶自己定義的攔截器
interceptors.addAll(client.interceptors());
//系統(tǒng)提供的重試攔截器院刁,失敗后的重試和重定向
interceptors.add(retryAndFollowUpInterceptor);
//負責(zé)把用戶構(gòu)造的請求轉(zhuǎn)換為發(fā)送到服務(wù)器的請求 、把服務(wù)器返回的響應(yīng)轉(zhuǎn)換為用戶友好的響應(yīng) 處理 配置請求頭等信息
//從應(yīng)用程序代碼到網(wǎng)絡(luò)代碼的橋梁粪狼。首先退腥,它根據(jù)用戶請求構(gòu)建網(wǎng)絡(luò)請求任岸。然后它繼續(xù)呼叫網(wǎng)絡(luò)。最后狡刘,它根據(jù)網(wǎng)絡(luò)響應(yīng)構(gòu)建用戶響應(yīng)享潜。
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//處理 緩存配置 根據(jù)條件(存在響應(yīng)緩存并被設(shè)置為不變的或者響應(yīng)在有效期內(nèi))返回緩存響應(yīng)
//設(shè)置請求頭(If-None-Match、If-Modified-Since等) 服務(wù)器可能返回304(未修改)
//可配置用戶自己設(shè)置的緩存攔截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//連接攔截器 這里才是真正的請求網(wǎng)絡(luò)
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//配置okhttpClient 時設(shè)置的networkInterceptors
//返回觀察單個網(wǎng)絡(luò)請求和響應(yīng)的不可變攔截器列表嗅蔬。
interceptors.addAll(client.networkInterceptors());
}
//執(zhí)行流操作(寫出請求體剑按、獲得響應(yīng)數(shù)據(jù)) 負責(zé)向服務(wù)器發(fā)送請求數(shù)據(jù)、從服務(wù)器讀取響應(yīng)數(shù)據(jù)
//進行http請求報文的封裝與請求報文的解析
interceptors.add(new CallServerInterceptor(forWebSocket));
//創(chuàng)建責(zé)任鏈
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
//執(zhí)行 責(zé)任鏈
return chain.proceed(originalRequest);
}
看下 RealInterceptorChain 的實現(xiàn)
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
//創(chuàng)建新的攔截鏈澜术,鏈中的攔截器集合index+1
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
// 執(zhí)行當(dāng)前的攔截器
Interceptor interceptor = interceptors.get(index);
// 執(zhí)行攔截器
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;
}
根據(jù)上面的代碼 我們可以看出艺蝴,新建了一個RealInterceptorChain 責(zé)任鏈 并且 index+1,然后 執(zhí)行interceptors.get(index); 返回Response鸟废。
責(zé)任鏈中每個攔截器都會執(zhí)行chain.proceed()方法之前的代碼猜敢,等責(zé)任鏈最后一個攔截器執(zhí)行完畢后會返回最終的響應(yīng)數(shù)據(jù),而chain.proceed() 方法會得到最終的響應(yīng)數(shù)據(jù)盒延,這時就會執(zhí)行每個攔截器的chain.proceed()方法之后的代碼缩擂,其實就是對響應(yīng)數(shù)據(jù)的一些操作。
結(jié)合源碼添寺,可以得到如下結(jié)論:
攔截器按照添加順序依次執(zhí)行
攔截器的執(zhí)行從RealInterceptorChain.proceed()開始胯盯,進入到第一個攔截器的執(zhí)行邏輯
每個攔截器在執(zhí)行之前,會將剩余尚未執(zhí)行的攔截器組成新的RealInterceptorChain
攔截器的邏輯被新的責(zé)任鏈調(diào)用next.proceed()切分為start畦贸、next.proceed陨闹、end這三個部分依次執(zhí)行
next.proceed() 所代表的其實就是剩余所有攔截器的執(zhí)行邏輯
所有攔截器最終形成一個層層內(nèi)嵌的嵌套結(jié)構(gòu)
了解了上面攔截器的構(gòu)造過程,我們再來一個個的分析每個攔截器的功能和作用薄坏。
從代碼來看趋厉,總共添加了五個攔截器(不包含自定義的攔截器如client.interceptors和client.networkInterceptors,這兩個后面再解釋)胶坠。
我們本次分享君账,只做整體框架的解讀,具體每個攔截器的處理不在此做出贅述沈善。
- retryAndFollowUpInterceptor——失敗和重定向攔截器
- BridgeInterceptor——封裝request和response攔截器
- CacheInterceptor——緩存相關(guān)的過濾器乡数,負責(zé)讀取緩存直接返回、更新緩存
- ConnectInterceptor——連接服務(wù)闻牡,負責(zé)和服務(wù)器建立連接 這里才是真正的請求網(wǎng)絡(luò)
- CallServerInterceptor——執(zhí)行流操作(寫出請求體净赴、獲得響應(yīng)數(shù)據(jù)) 負責(zé)向服務(wù)器發(fā)送請求數(shù)據(jù)、從服務(wù)器讀取響應(yīng)數(shù)據(jù) 進行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();
}
}
執(zhí)行
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);
}
執(zhí)行結(jié)果為:
Interceptor_A
Interceptor_B
Interceptor_C
result = A_B_C
參考博客