1. 程式人生 > >OkHttp3.0攔截器原理——責任鏈模式

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中實際各個攔截器的呼叫順序,方便大家比照一下

 

       以上就是攔截器的整個流程,關於攔截器的具體運用,我將在另一篇文章中詳細闡述