Okhttp的Interceptor攔截器原始碼解析

檸檬茶就是力量發表於2019-07-23

攔截器的作用在APP開發中是相當重要的,這篇文章分析一下Okhttp中是怎麼實現一條攔截器鏈,希望能幫助大家更好去了解攔截器的作用

幾個關鍵類以及介面

  • RealInterceptorChain

  • Interceptor

RealInterceptorChain

RealInterceptorChain實現了Interceptor介面,呼叫源頭來自於RealCallgetResponseWithInterceptorChain方法

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    /**
    *  1
    */
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));
    /**
    *  2
    */
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }
複製程式碼

1. 第一處是把自定義的攔截器先加入進去,然後把okhttp內建的一些攔截器按照功能順序add進list裡

2. 第二處是整個攔截器工作的源頭,先new了一個RealInterceptorChain,index為0,把初始的request傳了進去,然後呼叫proceed獲取請求的response

接下來看一下proceed方法的具體實現,忽略掉一些檢查

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;
    /**
    *  1
    */
    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    return response;
  }
複製程式碼
先是檢查一下index是否超出interceptors也就是攔截器list的長度,接著又new了一個RealInterceptorChain,把當前RealInterceptorChain的一些引數屬性都傳了進去,並且在這裡把index + 1,這個地方很重要,在這裡可以把RealInterceptorChain想象成把攔截器給包裝了起來,然後用下一個攔截器生成一個新的RealInterceptorChain中,然後把index+1下標的chain傳進了當前攔截器的intercept方法裡,也就是我們自定義攔截器的時候需要重寫的intercept方法,也就是說我們新增的攔截器裡的intercept方法中RealInterceptorChain物件,實際上裡面包含有整個request以及下一個攔截器。所以就形成了一條鏈,每一個攔截器都持有下一個攔截器經過包裝之後的RealInterceptorChain物件,直到攔截器鏈的最後一個攔截器CallServerInterceptor 這個攔截器會做最後的處理,然後開始請求生成Response並且返回。攔截器可以通過intercept方法獲取下一個攔截器returnresponse,而且會通過proceed方法向下一個攔截器傳遞自己處理過的Requeset

到這裡總結一下各個方法以及類的作用

  • RealInterceptorChain

包裝了攔截器以及網路請求的資訊

  • RealInterceptorChain.proceed

引數中有Request,是上一個攔截器包裝過後的Request,然後將下一個攔截器和整個Request的資訊包裝成RealInterceptorChain,並且會呼叫當前攔截器的intercept方法把下一個攔截器(RealInterceptorChain)傳進去,並且獲取到Response

  • Interceptor.intercept

方法引數是下一個Chain也就是RealInterceptorChain,然後呼叫RealInterceptorChain.request()去獲取請求,呼叫RealInterceptorChain.proceed()去獲取Response

這三點結合在一起,就形成了一條鏈,假設有攔截器A/B/C,RealInterceptorChain A/B/C

RA.proceed->A.intercept(呼叫下一個攔截器的proceed)->RB.proceed->B.intercept,這樣的寫法,可以讓每個攔截器都獲取到上一個攔截器包裝過的Request並且自己處理之後再傳給下一個攔截器,然後最後一個攔截器生成Response之後,從攔截器鏈尾部往頭部攔截器一層層return,就形成了一個完整的攔截器鏈處理邏輯

相關文章