OkHttp3深度源碼解析(一),體會OkHttp3設計模式的妙處

一、okhttp背景…

二、使用步驟
1、創建OkHttpClient;
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
這一個過程到底做了什麼?
最張調用 OkHttpClient(Builder builder)得到實例並賦值。
賦值了哪些參數?

private 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);
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    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;
  }

參數解釋:
1)dispatcher:請求的執行器,負責請求的同步執行、異步執行、取消、以及最多可以同時執行的請求數。
包含三個請求隊列:
readyAsyncCalls,準備執行的異步請求列隊,(當同時請求數大於maxRequests時,會將請求存入到這列隊)
runningAsyncCalls:正在執行的異步請求列隊(未取消和未結束)
runningSyncCalls:正在執行的同步請求列隊(未取消和未結束)

2)proxy:網絡的代理設置,可以通過他給網絡請求設置代理

3)protocols:支持的Protocol協議,Protocol和Url類似,java.net.URI.getScheme()返回url的協議(http, https, etc),而Protocol.get()返回的協議更加具體(http/1.0,http/1.1,h2,etc)

4)connectionSpecs : 支持套接字連接協議.

5)interceptors: 攔截器。可觀察每個調用的全部跨度

6)networkInterceptors : 攔截器。可觀察一個網絡請求和響應

7)proxySelector :代理服務器選擇器

8)cookieJar :提供cookie可持久化操作。

9)cache:緩存

10)internalCache:okhttp的內部緩存,使用者不應該使用它,用cache即可。

11)socketFactory :創建套接字的工廠類

12)sslSocketFactory:創建ssl套接字工廠類

13)certificateChainCleaner:證書

14)hostnameVerifier:主機名驗證

15)certificatePinner:約束所信任的證書

16)proxyAuthenticator:身份驗證代理服務器

17)authenticator:身份驗證代理服務器

18)connectionPool:連接池用於回收利用HTTP和HTTPS連接。

19)dns:dns服務器;默認使用系統的

20)followSslRedirects:是否支持sslhttp重定向,默認true

21)followRedirects:是否支持http重定向,默認true

22)retryOnConnectionFailure:連接失敗時是否重試,默認true

23)connectTimeout:連接超時

24)readTimeout:讀取超時

25)writeTimeout:寫入超時

參數有些多,大致瞭解可以幫我們更容易理清okhttp整體流程

2、創建Request;

  private Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tag = builder.tag != null ? builder.tag : this;
  }

參數說明,這個看着清爽:
1)url:請求地址
2)method :請求方法
3)headers :請求頭
4)body:請求體
5)tag:請求標記

3、創建Call,
Call = okHttpClient.newCall(Request);
實際上調用了

   protected RealCall(OkHttpClient client, Request originalRequest) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
  }

這裏添加 retryAndFollowUpInterceptor 攔截器,通過這個攔截實現了重新請求及取消請求功能

4、重頭戲來了。(這裏先看看異步請求),enqueue(Callback responseCallback);
1)開始執行請求:

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
如果已經被執行就拋異常,所以一個call就能調一次execute、enqueue。

2) client.dispatcher().enqueue(new AsyncCall(responseCallback));
調用該請求的client的執行器來執行該請求。
這裏先創建了一個Runable的子類AsyncCall。

3)dispatcher 類中

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

看看請求列表有沒有滿。沒有滿,加入到正在執行列表,然後直接執行。否則放到等待隊列。

4)AsyncCall類中,直接在代碼中註解了

  @Override protected void execute() {
        //標記有沒有執行回調
      boolean signalledCallback = false;
      try {
      //核心、獲取到response,看下面註釋
        Response response = getResponseWithInterceptorChain();

        //如果取消的就直接回調onFailure,傳入new IOException("Canceled")異常。
        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 {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
      //最後,結束這個call,看下面
        client.dispatcher().finished(this);
      }
    }

    private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      if (promoteCalls) promoteCalls();//promoteCalls()是爲了在滿足要下(正在執行的異步任務數小於maxRequests)把準備請求列裏的請求轉至正在請求隊列,並執行它。
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();//如果分發器沒有需要執行的工作,處理idle狀態,會執行該回調
    }
  }

RealCall類裏面 
  private Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();

    //下面是添加一系列攔截器,個人覺得這裏是體現okhttp精華所在的勝地,看到這裏,都會激動的不要不要的!
    interceptors.addAll(client.interceptors());
    //網絡重試及取消的處理
    interceptors.add(retryAndFollowUpInterceptor);
    //cookie處理
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //okhttp的內部緩存處理
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //打開目標服務器的連接
    interceptors.add(new ConnectInterceptor(client));

    //如果不是forWebSocket,添加網絡重試及取消攔截器
    if (!retryAndFollowUpInterceptor.isForWebSocket()) {
      interceptors.addAll(client.networkInterceptors());
    }
    網絡請求在這個攔截器裏面
    interceptors.add(new CallServerInterceptor(
        retryAndFollowUpInterceptor.isForWebSocket()));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

  RealInterceptorChain類中 貼出核心代碼
  public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,
      Connection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

      Call the next interceptor in the chain.
      獲取到下個攔截(攔截是從0開關順序執行的,結後執行是的CallServerInterceptor攔截器,所以在CallServerInterceptor攔截器中就看不到Chain.proceed(Request request)了)
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpStream, connection, index + 1, request);
    Interceptor interceptor = interceptors.get(index);
    //讓下個攔截去處理所要處理的邏輯
    Response response = interceptor.intercept(next);

    return response;
  }

三、總結
看完後
美妙無窮

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章