Okhttp3 攔截器鏈過程淺析(四)

攔截器:Okhttp中提供的一種強(qiáng)大的機(jī)制,可以實(shí)現(xiàn)網(wǎng)絡(luò)監(jiān)聽、請(qǐng)求/響應(yīng)重寫、請(qǐng)求失敗重試等功能的實(shí)現(xiàn)(攔截器不區(qū)分異步/同步)

Okhttp不管是異步/同步,在RealCall.java中都會(huì)執(zhí)行Response result = getResponseWithInterceptorChain();

  • 同步
RealCall.java

@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();//執(zhí)行該方法
      .....省略無用代碼
  }

  • 異步
RealCall.java

@Override public void enqueue(Callback responseCallback) {
    ...省略無用代碼
    client.dispatcher().enqueue(new AsyncCall(responseCallback));//跟到AsyncCall中
  }

==============================分割線=========================

AsyncCall.execute();

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();//異步也是執(zhí)行該方法
        ....省略無用代碼
    }

接下來看一下getResponseWithInterceptorChain()具體做了什么操作,源碼如下:

//方法字面意思:得到一個(gè)具有攔截器鏈的響應(yīng)
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()));//橋接攔截器
    interceptors.add(new CacheInterceptor(client.internalCache()));//緩存攔截器
    interceptors.add(new ConnectInterceptor(client));//網(wǎng)絡(luò)連接攔截器
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    //攔截器鏈
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    //執(zhí)行RealInterceptorChain.proceed();方法,下面將具體分析
    return chain.proceed(originalRequest);
  }

上面的getResponseWithInterceptorChain()是通過RealInterceptorChain.proceed();方法得到一個(gè)攔截器鏈,下面具體看一下proceed()方法:

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

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    // 在這里,得到了 next 下一個(gè)鏈,構(gòu)造函數(shù)中將 index+1 
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    //interceptors 就是從構(gòu)造函數(shù)中,得到的List<Interceptpr>
    //也就是在RealCall.getResponseWithInterceptorChain();中添加的所有的攔截器
    Interceptor interceptor = interceptors.get(index);
    //在這里,執(zhí)行攔截器的intercept();方法
    //在具體攔截器的intercept()方法中,又會(huì)調(diào)用next chain的proceed();方法
    //構(gòu)成了一個(gè)鏈
    Response response = interceptor.intercept(next);

    ....省略部分代碼

    return response;
  }

proceed()方法執(zhí)行過程大概是:
在內(nèi)部將index+1,得到下一個(gè)RealInterceptorChain,通過具體的攔截器的intercept()方法,繼續(xù)執(zhí)行下一個(gè)鏈的proceed();方法,依次直到最后一個(gè)攔截器,從而形成一個(gè)鏈(有點(diǎn)類似于遞歸,依次往內(nèi)部請(qǐng)求,結(jié)果從最內(nèi)部一層一層傳到最外層)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容