本系列文章:
OkHttp源碼徹底解析(三)OkHttp3.0攔截器原理——責任鏈模式
目錄
什麼是攔截器
攔截器是OkHttp中提供一種強大機制,它可以實現網絡監聽、請求以及響應重寫、請求失敗重試等功能。
Okhttp3.0中的攔截器有點像安卓裏面的觸控反饋的Interceptor。既一個網絡請求,按一定的順序,經由多個攔截器進行處理,該攔截器可以決定自己處理並且返回我的結果,也可以選擇向下繼續傳遞,讓後面的攔截器處理返回它的結果。這個設計模式叫做責任鏈模式。
與Android中的觸控反饋interceptor的設計略有不同的是,後者通過返回true 或者 false 來決定是否已經攔截。而OkHttp這裏的攔截器通過函數調用的方式,講參數傳遞給後面的攔截器的方式進行傳遞。這樣做的好處是攔截器的邏輯比較靈活,可以在後面的攔截器處理完並返回結果後仍然執行自己的邏輯;缺點是邏輯沒有前者清晰。
攔截器中的類
在攔截器這種結構中,我們只要能掌握好以下兩個角色就可以了
Interceptor 這個我們的攔截器接口,所有攔截器都要實現它
Chain 這個是串聯起攔截器流程的鏈
下面來看看這兩個類中的邏輯:
1.Chain中持有所有要調用的Interceptor 的列表集合incps
Chain中的proceed方法:調用調用每個Interceptor 的intercept方法 會把Chain自己和去掉第一個Interceptor 的incpts(已經調用完的Interceptor 後面就不調用)作爲參數傳入
2.Interceptor 中
intercept方法:處理自身負責的邏輯,該方法在Chain中被調用並傳入Chain本身,在執行了自身的邏輯之後,調用傳入的Chain的proceed
總結就是,Chain中的procced與Interceptor 中的intercept相互循環調用,而procced中每次Chain中的Interceptor 都會往後移動一位,所以這個循環當所以Interceptor 執行過後就會終止。
攔截器中的源碼
那我們來看看他們通過源碼來看看他們內部是如何做到有序地串聯的。
攔截器接口的源碼:
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
其中的Chain就是我們是用來傳遞的鏈。這裏的傳遞邏輯僞代碼如下:
代碼的最外層邏輯(下面這個不只是chain的,是整個的僞代碼)
Request request = new Request(){};
Arrlist<Interceptor> incpts = new Arrlist();
Interceptor icpt0 = new Interceptor(){ XXX };
Interceptor icpt1 = new Interceptor(){ XXX };
Interceptor icpt2 = new Interceptor(){ XXX };
...
incpts.add(icpt0);
incpts.add(icpt1);
incpts.add(icpt2);
Interceptor.Chain chain = new MyChain(incpts);
chain.proceed(request);
下面就是最關鍵的源碼部分,基本上所以的責任鏈Chain都是按着這個模板來的
封裝的Chain的內部邏輯
public class MyChain implement Interceptor.Chain{
Arrlist<Interceptor> incpts;
int index = 0;
public MyChain(Arrlist<Interceptor> incpts){
this(incpts, 0);
}
public MyChain(Arrlist<Interceptor> incpts, int index){
this.incpts = incpts;
this.index =index;
}
public void setInterceptors(Arrlist<Interceptor> incpts ){
this.incpts = incpts;
}
@override
Response proceed(Request request) throws IOException{
Response response = null;
...
//取出第一個interceptor來處理
Interceptor incpt = incpts.get(index);
//生成下一個Chain,index標識當前Interceptor的位置。
Interceptor.Chain nextChain = new MyChain(incpts,index+1);
response = incpt.intercept(nextChain);
...
return response;
}
}
而各個Interceptor源碼中的實現:
public class MyInterceptor implement Intercetpor{
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//前置攔截邏輯
...
Response response = chain.proceed(request);//傳遞Interceptor
//後置攔截邏輯
...
return response;
}
}
在這個鏈中,最後的一個Interceptor一般用作生成最後的Response操作,它不會再繼續傳遞給下一個。
攔截器源碼的邏輯流程
上面就是整個邏輯的源碼了,雖然不多,但是邏輯有點繞(莫慌,看了下面你就會懂了)
這裏爲了讓調用順序更直觀些,直接把源碼的調用關係畫出
這是Interceptor和Chain的源碼以及方法的調用關係,是不是有點像遞歸函數的感覺。不過兩者還是有區別的,遞歸函數是不斷調用自身,而這種攔截器的邏輯是兩個類(或者說是類內部的方法)不斷相互調用,以某個條件作爲終結。
諸如此類的邏輯還有 自定義控件的點擊事件攔截,ClassLoader的雙親委派機制,其他的這裏就不做展開
關於其中的順序,用流程圖來看更直觀 (其中,所有Chain都是同一個,括號內編號表示第幾次調用proceed方法)
說了這麼多都是源碼,這裏附上OkHttp中實際各個攔截器的調用順序,方便大家比照一下
以上就是攔截器的整個流程,關於攔截器的具體運用,我將在另一篇文章中詳細闡述