OkHttp3 源碼解析執(zhí)行流程

OkHttp是一款網(wǎng)絡(luò)請求框架浑塞,【OkHttp傳送門】,為了在開發(fā)中使用的更加得心應(yīng)手季惩,必然的要去探究其源碼录粱,分析其中的工作原理腻格,而且還能學(xué)習(xí)框架的設(shè)計(jì)思想画拾。文章主要對OkHttp整體的工作流程進(jìn)行分析,所以一些操作方法并沒有涉及菜职,讀者可以通過傳送門閱讀文檔自行實(shí)踐青抛。在分析之前,先看一張整體的流程圖(本文內(nèi)容會根據(jù)圖的流程展開):

okhttp流程.png

OkHttp請求網(wǎng)絡(luò)的簡單示例

private static final String URL_CONTENT = "https://www.baidu.com/";

    public static void doOkHttp() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)  //連接失敗后進(jìn)行重連
                .build();

        final Request request = new Request.Builder()              
                .url(URL_CONTENT)
                .build();
        
        //異步方式請求網(wǎng)絡(luò)
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請求失敗
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請求成功,對response進(jìn)行處理
                
            }
        });
    }

上面的代碼酬核,首先創(chuàng)建一個(gè)okHttpClient對象蜜另,調(diào)用newCall()并且request作為參數(shù)傳入,然后執(zhí)行enqueue()嫡意,并且new一個(gè)Callback举瑰,請求結(jié)果的回調(diào),這個(gè)過程是異步的蔬螟。

//execute()是同步的方式請求網(wǎng)絡(luò)此迅,會阻塞UI線程,所以一般情況都是通過異步的方式請求網(wǎng)絡(luò)
okHttpClient.newCall(request).execute();

1旧巾、OkHttpClient的build()過程耸序。

public Builder() {
      dispatcher = new Dispatcher();  //異步請求調(diào)度器
      protocols = DEFAULT_PROTOCOLS;//請求協(xié)議集合,默認(rèn)為http/1.1和Http/2
      connectionSpecs = DEFAULT_CONNECTION_SPECS;//連接規(guī)格
      eventListenerFactory = EventListener.factory(EventListener.NONE);//事件監(jiān)聽器
      proxySelector = ProxySelector.getDefault();//代理選擇器
      cookieJar = CookieJar.NO_COOKIES;//http cookies 提供持久化策略
      socketFactory = SocketFactory.getDefault(); //socket工廠類
      hostnameVerifier = OkHostnameVerifier.INSTANCE;//對host基本接口的驗(yàn)證
      certificatePinner = CertificatePinner.DEFAULT; //約束的信任證書
      proxyAuthenticator = Authenticator.NONE;//代理身份認(rèn)證
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();//連接復(fù)用池
      dns = Dns.SYSTEM;//默認(rèn)使用系統(tǒng)的dns
      followSslRedirects = true; //遵循SSL重定向
      followRedirects = true;//普通重定向
      retryOnConnectionFailure = true;//連接失敗后進(jìn)行重新連接
      connectTimeout = 10_000;//連接超時(shí)時(shí)間
      readTimeout = 10_000;//讀取數(shù)據(jù)超時(shí)時(shí)間
      writeTimeout = 10_000;//發(fā)送數(shù)據(jù)超時(shí)時(shí)間
      pingInterval = 0;//時(shí)間間隔
    }

public OkHttpClient build() {
      return new OkHttpClient(this);
    }
OkHttpClient(Builder builder) {
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);//自定義的攔截器
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);//網(wǎng)絡(luò)攔截器
    this.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;//創(chuàng)建OkHttpClient對象時(shí)的自定義緩存
    this.internalCache = builder.internalCache;//內(nèi)部緩存
    this.socketFactory = builder.socketFactory;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      X509TrustManager trustManager = systemDefaultTrustManager();
      this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;

    if (interceptors.contains(null)) {
      throw new IllegalStateException("Null interceptor: " + interceptors);
    }
    if (networkInterceptors.contains(null)) {
      throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
    }
  }

通過建造者模式創(chuàng)建OkHttpClient對象鲁猩,并且配置各種參數(shù)坎怪。

2、Request的Builder()的過程

public Builder() {
      this.method = "GET"; //請求方法廓握,默認(rèn)GET
      this.headers = new Headers.Builder();//創(chuàng)建請求頭
    }

public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }

Request(Builder builder) {
    this.url = builder.url; //請求url
    this.method = builder.method;//請求方法
    this.headers = builder.headers.build();//請求頭
    this.body = builder.body;//請求體
    this.tag = builder.tag != null ? builder.tag : this;
  }

Request也是以建造者模式創(chuàng)建對象搅窿,配置參數(shù)。關(guān)于HTTP報(bào)文結(jié)構(gòu)圖(左圖對應(yīng)Request隙券,右圖對應(yīng)Response):


HTTP報(bào)文結(jié)構(gòu).png

3戈钢、okHttpClient.newCall()

public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

//RealCall # newRealCall
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }

調(diào)用newCall()實(shí)際返回的是一個(gè)RealCall(繼承自Call)對象。RealCall內(nèi)部封裝了網(wǎng)絡(luò)請求和請求結(jié)果回調(diào)是尔。那么殉了,上面的異步請求實(shí)際調(diào)用的是RealCall的enqueue()方法。

4拟枚、RealCall # enqueue()

public void enqueue(Callback responseCallback) {
    synchronized (this) {
      //若任務(wù)已經(jīng)執(zhí)行薪铜,則拋出IllegalStateException
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //跟蹤調(diào)用堆棧
    captureCallStackTrace();
    //監(jiān)聽開始事件
    eventListener.callStart(this);
    // 1
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

上面代碼的核心是注釋1處,client.dispatcher()返回一個(gè)Dispatcher對象恩溅,異步請求調(diào)度器隔箍,里面會對任務(wù)進(jìn)行分辨,是立刻執(zhí)行還是放入等待隊(duì)列脚乡。AsyncCall繼承NamedRunnable(實(shí)現(xiàn)了Runnable接口)類蜒滩,接著進(jìn)入Dispatcher的enqueue()方法:

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

從代碼可以發(fā)現(xiàn)滨达,Dispatcher的enqueue()是一個(gè)同步方法,maxRequests是最大請求數(shù)(值為64)俯艰,maxRequestsPerHost是Host最大請求數(shù)據(jù)(值為5)捡遍,當(dāng)滿足這兩個(gè)條件時(shí),把任務(wù)添加到執(zhí)行隊(duì)列runningAsyncCalls竹握,立刻執(zhí)行画株,否則加入等待隊(duì)列readyAsyncCalls,等待異步調(diào)用啦辐。executorService()內(nèi)部創(chuàng)建了一個(gè)執(zhí)行任務(wù)的線程池谓传,并且返回一個(gè)執(zhí)行對象ExecutorService。
executorService()的內(nèi)部實(shí)現(xiàn):

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;
  }

以單例模式中的懶漢模式創(chuàng)建了一個(gè)線程池芹关。其實(shí)上面創(chuàng)建的線程池和我們直接用Executors的newCachedThreadPool()創(chuàng)建是類似的续挟,核心線程數(shù)為0,線程空閑時(shí)的超時(shí)時(shí)間60s侥衬,直接提交策略诗祸。關(guān)于線程池的分析,可以閱讀【探索Java 線程池】這篇文章浇冰。在這里贬媒,往線程池中添加的任務(wù)對象是AsyncCall,那么看看AsyncCall的內(nèi)部實(shí)現(xiàn):

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();
        //根據(jù)是否取消RetryAndFollowUpInterceptor,分別回調(diào)onFailure或onResponse
        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 {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {  
        //請求完畢肘习,移除runningAsyncCalls中當(dāng)前執(zhí)行的Call际乘。
        //并且查找等待隊(duì)列readyAsyncCalls是否存在任務(wù),存在漂佩,則添加執(zhí)行隊(duì)列runningAsyncCalls脖含,然后執(zhí)行任務(wù)
        //如果runningAsyncCalls不存在任務(wù),且idleCallback不為null投蝉,則啟動空閑狀態(tài)Runnable
        client.dispatcher().finished(this);
      }
    }
  }

NamedRunnable實(shí)現(xiàn)了Runnable接口养葵,在其run()方法內(nèi)部調(diào)用了execute()方法,這里運(yùn)用了設(shè)計(jì)模式中的模板模式瘩缆,那么关拒,這里就把任務(wù)交給了AsyncCall的execute()方法。通過代碼的注釋可以知道庸娱,把請求交由了getResponseWithInterceptorChain()方法着绊,這個(gè)方法直譯過來意思就是:用攔截器鏈獲取響應(yīng)報(bào)文。而方法內(nèi)部也正運(yùn)用了設(shè)計(jì)模式中的責(zé)任鏈模式熟尉。

模板模式
優(yōu)點(diǎn):封裝不變部分归露,擴(kuò)展可變部分;提取公共部分代碼斤儿,便于維護(hù)剧包。
缺點(diǎn):在代碼閱讀方面可能會帶來相對的難度恐锦。

責(zé)任鏈模式
優(yōu)點(diǎn):對請求者和處理者關(guān)系解耦,提高了代碼靈活性疆液。
缺點(diǎn):如果處理者太多一铅,過多的遍歷會導(dǎo)致性能降低。

回到OkHttp的請求流程枚粘,上面已經(jīng)把任務(wù)交由了getResponseWithInterceptorChain()方法馅闽,那么飘蚯,看下其內(nèi)部實(shí)現(xiàn)馍迄。

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    //初始化OkHttpClient對象時(shí)添加的自定義interceptors
    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) {  
      //添加用戶自定義的networkInterceptors
      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());

    return chain.proceed(originalRequest);
  }

getResponseWithInterceptorChain()內(nèi)部添加各種攔截器,利用RealInterceptorChain將已有的攔截器進(jìn)行串聯(lián)局骤,然后proceed()開始遍歷攔截器攀圈。

 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
  ... ....//省略部分代碼

    // Call the next interceptor in the chain.
    //遍歷攔截器鏈,index代表責(zé)任鏈中攔截器的下標(biāo)峦甩,初始值為0
    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;
  }

5赘来、分析各個(gè)攔截器的作用

  • RetryAndFollowUpInterceptor:在連接失敗后進(jìn)行重新連接,必要時(shí)進(jìn)行重定向凯傲,如果調(diào)用被取消犬辰,可能會拋出IOException
  • BridgeInterceptor:構(gòu)建訪問網(wǎng)絡(luò)的橋梁,首先冰单,將用戶請求轉(zhuǎn)換成網(wǎng)絡(luò)請求幌缝,然后訪問網(wǎng)絡(luò),最后將網(wǎng)絡(luò)響應(yīng)轉(zhuǎn)換成用戶響應(yīng)诫欠。
  • CacheInterceptor:緩存攔截器涵卵,從緩存中獲取服務(wù)器請求,或者把服務(wù)器響應(yīng)寫入緩存中荒叼。
  • ConnectInterceptor:打開一個(gè)連接轿偎,去連接目標(biāo)服務(wù)器。
  • CallServerInterceptor:攔截器鏈中的最后一個(gè)鏈點(diǎn)被廓,通過網(wǎng)絡(luò)請求服務(wù)器坏晦。

鏈?zhǔn)綀?zhí)行流程:

鏈?zhǔn)搅鞒?png

5.1、RetryAndFollowUpInterceptor # intercept()

public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Call call = realChain.call();
    EventListener eventListener = realChain.eventListener();
    
    //用于分配一個(gè)到服務(wù)器特定的HttpStream嫁乘,內(nèi)部封裝了ConnectionPool連接池昆婿,管理Http的連接
    StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
        createAddress(request.url()), call, eventListener, callStackTrace);
    this.streamAllocation = streamAllocation;

    int followUpCount = 0;
    Response priorResponse = null;
    //開啟輪詢
    while (true) {
      //若已取消連接,釋放資源
      if (canceled) {
        streamAllocation.release();
        throw new IOException("Canceled");
      }

      Response response;
      boolean releaseConnection = true;
      try {
        //調(diào)用下一個(gè)攔截器
        response = realChain.proceed(request, streamAllocation, null, null);
        releaseConnection = false;
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
          throw e.getLastConnectException();
        }
        releaseConnection = false;
        continue;
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
        if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
        releaseConnection = false;
        continue;
      } finally {
        // We're throwing an unchecked exception. Release any resources.
        if (releaseConnection) {
          streamAllocation.streamFailed(null);
          streamAllocation.release();
        }
      }

      // Attach the prior response if it exists. Such responses never have a body.
      //檢測前一個(gè)Response
      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                    .body(null)
                    .build())
            .build();
      }
      
      Request followUp = followUpRequest(response, streamAllocation.route());
      //followUp為null亦渗,表示不要重定向挖诸,釋放資源并且返回response
      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        return response;
      }
      //關(guān)閉response的body
      closeQuietly(response.body());
      //最大重定向次數(shù)20
      if (++followUpCount > MAX_FOLLOW_UPS) {
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }
      
      //如果是不可重復(fù)的請求體,拋出異常
      if (followUp.body() instanceof UnrepeatableRequestBody) {
        streamAllocation.release();
        throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
      }

      //檢測地址是否相同法精,釋放舊連接多律,重新創(chuàng)建一個(gè)新的連接
      if (!sameConnection(response, followUp.url())) {
        streamAllocation.release();
        streamAllocation = new StreamAllocation(client.connectionPool(),
            createAddress(followUp.url()), call, eventListener, callStackTrace);
        this.streamAllocation = streamAllocation;
      } else if (streamAllocation.codec() != null) {
        throw new IllegalStateException("Closing the body of " + response
            + " didn't close its backing stream. Bad interceptor?");
      }

      request = followUp;
      priorResponse = response;
    }
  }

5.2痴突、BridgeInterceptor # intercept()

public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();
    //將用戶的Request構(gòu)造成服務(wù)器的Request
    RequestBody body = userRequest.body();
    if (body != null) {     //請求體存在,進(jìn)行轉(zhuǎn)換
      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }
    }

    if (userRequest.header("Host") == null) {
      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }
    
    //保持連接
    if (userRequest.header("Connection") == null) {
      requestBuilder.header("Connection", "Keep-Alive");
    }
 
    //使用Gzip壓縮
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }
  
    //設(shè)置cookies
    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }
    
    //傳入已構(gòu)造好的服務(wù)器Request狼荞,調(diào)用下一個(gè)攔截器辽装,獲取服務(wù)器的networkResponse 
    Response networkResponse = chain.proceed(requestBuilder.build());
    
    //保存networkResponse的cookie
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
   
    //后續(xù)則是把networkResponse構(gòu)造成用戶的response
    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);

    if (transparentGzip
        && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
        && HttpHeaders.hasBody(networkResponse)) {
      GzipSource responseBody = new GzipSource(networkResponse.body().source());
      Headers strippedHeaders = networkResponse.headers().newBuilder()
          .removeAll("Content-Encoding")
          .removeAll("Content-Length")
          .build();
      responseBuilder.headers(strippedHeaders);
      String contentType = networkResponse.header("Content-Type");
      responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
    }

    return responseBuilder.build();
  }

5.3、CacheInterceptor # intercept()

public Response intercept(Chain chain) throws IOException {
    Response cacheCandidate = cache != null
        ? cache.get(chain.request())
        : null;
    //獲取當(dāng)前時(shí)間
    long now = System.currentTimeMillis();
    
    //獲取緩存策略
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    Request networkRequest = strategy.networkRequest;
    Response cacheResponse = strategy.cacheResponse;

    //從緩存中追蹤Response
    if (cache != null) {
      cache.trackResponse(strategy);
    }

    //如果緩存不適用相味,則關(guān)閉
    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); 
    }

    // 如果網(wǎng)絡(luò)被禁止拾积,且緩存為空,則返回失敗
    if (networkRequest == null && cacheResponse == null) {
      return new Response.Builder()
          .request(chain.request())
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(Util.EMPTY_RESPONSE)
          .sentRequestAtMillis(-1L)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();
    }

    // 不需要網(wǎng)絡(luò)時(shí)丰涉,從緩存中獲取
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }

    Response networkResponse = null;
    try {
      //調(diào)用下一個(gè)攔截者拓巧,從網(wǎng)絡(luò)獲取Response 
      networkResponse = chain.proceed(networkRequest);
    } finally {
      // 關(guān)閉body,防止內(nèi)存泄露
      if (networkResponse == null && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }

    // 如果緩存中存在Response一死,同時(shí)檢測networkResponse是否被修改
    if (cacheResponse != null) {
      if (networkResponse.code() == HTTP_NOT_MODIFIED) {
        Response response = cacheResponse.newBuilder()
            .headers(combine(cacheResponse.headers(), networkResponse.headers()))
            .sentRequestAtMillis(networkResponse.sentRequestAtMillis())
            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
        networkResponse.body().close();

        // Update the cache after combining headers but before stripping the
        // Content-Encoding header (as performed by initContentStream()).
        //更新緩存中的數(shù)據(jù)至最新
        cache.trackConditionalCacheHit();
        cache.update(cacheResponse, response);
        return response;
      } else {
        closeQuietly(cacheResponse.body());
      }
    }

    //構(gòu)建response 
    Response response = networkResponse.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();

    //把之前未緩存的添加至緩存中
    if (cache != null) {
      if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
        // Offer this request to the cache.
        CacheRequest cacheRequest = cache.put(response);
        return cacheWritingResponse(cacheRequest, response);
      }

      if (HttpMethod.invalidatesCache(networkRequest.method())) {
        try {
          cache.remove(networkRequest);
        } catch (IOException ignored) {
          // The cache cannot be written.
        }
      }
    }

    return response;
  }

5.4肛度、ConnectInterceptor # intercept()

public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    StreamAllocation streamAllocation = realChain.streamAllocation();

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean doExtensiveHealthChecks = !request.method().equals("GET");

    //獲取httpCodec 對象,HttpCodec的實(shí)現(xiàn)類有Http1Codec和Http2Codec
    //分別對應(yīng)Http1.1和Http2
    //HttpCodec主要是對Http請求和Http響應(yīng)進(jìn)行編解碼
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();
    
    //調(diào)用下一個(gè)攔截器
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }

StreamAllocation的newStream()方法內(nèi)部實(shí)現(xiàn)

public HttpCodec newStream(
      OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
    int connectTimeout = chain.connectTimeoutMillis();
    int readTimeout = chain.readTimeoutMillis();
    int writeTimeout = chain.writeTimeoutMillis();
    int pingIntervalMillis = client.pingIntervalMillis();
    boolean connectionRetryEnabled = client.retryOnConnectionFailure();

    try {
      //尋找一個(gè)可用連接
      RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
          writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
      //根據(jù)具體的resultConnection 創(chuàng)建resultCodec對象
      HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);

      synchronized (connectionPool) {
        codec = resultCodec;
        return resultCodec;
      }
    } catch (IOException e) {
      throw new RouteException(e);
    }
  }

5.5投慈、CallServerInterceptor # intercept()

public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    HttpCodec httpCodec = realChain.httpStream();
    StreamAllocation streamAllocation = realChain.streamAllocation();
    RealConnection connection = (RealConnection) realChain.connection();
    Request request = realChain.request();
    
    long sentRequestMillis = System.currentTimeMillis();

    realChain.eventListener().requestHeadersStart(realChain.call());
    //寫入請求頭
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);

    Response.Builder responseBuilder = null;
    
    //檢測是否有body的請求方法
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {

      //如果請求頭是"100-continue"承耿,等待服務(wù)器的響應(yīng)
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        realChain.eventListener().responseHeadersStart(realChain.call());
        responseBuilder = httpCodec.readResponseHeaders(true);
      }

      if (responseBuilder == null) {
        // Write the request body if the "Expect: 100-continue" expectation was met.
        realChain.eventListener().requestBodyStart(realChain.call());        
        long contentLength = request.body().contentLength();
       
        //將請求體轉(zhuǎn)換成sink,并封裝在CountingSink 內(nèi)部
        CountingSink requestBodyOut =
            new CountingSink(httpCodec.createRequestBody(request, contentLength));
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);

        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
        realChain.eventListener()
            .requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
      } else if (!connection.isMultiplexed()) {
        // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
        // from being reused. Otherwise we're still obligated to transmit the request body to
        // leave the connection in a consistent state.
        streamAllocation.noNewStreams();
      }
    }

    httpCodec.finishRequest();

    //從httpCodec中獲取響應(yīng)頭
    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

    //構(gòu)建response 
    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    //如果服務(wù)器返回的狀態(tài)碼是100伪煤,再次嘗試讀取具體的response
    int code = response.code();
    if (code == 100) {
      // server sent a 100-continue even though we did not request one.
      // try again to read the actual response
      responseBuilder = httpCodec.readResponseHeaders(false);

      response = responseBuilder
              .request(request)
              .handshake(streamAllocation.connection().handshake())
              .sentRequestAtMillis(sentRequestMillis)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build();

      code = response.code();
    }

    realChain.eventListener()
            .responseHeadersEnd(realChain.call(), response);

    //如果是WebSocket加袋,并且返回狀態(tài)碼為101,表示響應(yīng)body為空
    if (forWebSocket && code == 101) {
      response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
      //讀取body
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }
     
    //如果響應(yīng)頭部是"close"抱既,關(guān)閉流
    if ("close".equalsIgnoreCase(response.request().header("Connection"))
        || "close".equalsIgnoreCase(response.header("Connection"))) {
      streamAllocation.noNewStreams();
    }
    
    //協(xié)議異常
    if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
      throw new ProtocolException(
          "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
    }

    return response;
  }

到這里职烧,OkHttp的執(zhí)行流程就分析完畢了。

關(guān)于OkHttp3系列的其它文章:
OkHttp3 源碼解析 連接池的復(fù)用
OkHttp3源碼解析內(nèi)部緩存

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝙砌,一起剝皮案震驚了整個(gè)濱河市阳堕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌择克,老刑警劉巖恬总,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肚邢,居然都是意外死亡壹堰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門骡湖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贱纠,“玉大人,你說我怎么就攤上這事响蕴∽缓福” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵浦夷,是天一觀的道長辖试。 經(jīng)常有香客問我辜王,道長,這世上最難降的妖魔是什么罐孝? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任呐馆,我火速辦了婚禮,結(jié)果婚禮上莲兢,老公的妹妹穿的比我還像新娘汹来。我一直安慰自己,他們只是感情好改艇,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布收班。 她就那樣靜靜地躺著,像睡著了一般遣耍。 火紅的嫁衣襯著肌膚如雪闺阱。 梳的紋絲不亂的頭發(fā)上炮车,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天舵变,我揣著相機(jī)與錄音,去河邊找鬼瘦穆。 笑死纪隙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扛或。 我是一名探鬼主播绵咱,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼熙兔!你這毒婦竟也來了悲伶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤住涉,失蹤者是張志新(化名)和其女友劉穎麸锉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舆声,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡花沉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了媳握。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碱屁。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蛾找,靈堂內(nèi)的尸體忽然破棺而出娩脾,到底是詐尸還是另有隱情,我是刑警寧澤打毛,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布柿赊,位于F島的核電站架曹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏闹瞧。R本人自食惡果不足惜绑雄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奥邮。 院中可真熱鬧万牺,春花似錦、人聲如沸洽腺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蘸朋。三九已至核无,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間藕坯,已是汗流浹背团南。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留炼彪,地道東北人吐根。 一個(gè)月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像辐马,于是被迫代替她去往敵國和親拷橘。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容