1. 程式人生 > >原始碼分析:Android Okhttp原始碼淺析(一)

原始碼分析:Android Okhttp原始碼淺析(一)

Okhttp的呼叫


分析原始碼,我們都需要通過呼叫來檢視原始碼的每一步都做了什麼事情。

看下非同步呼叫

 OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url("").build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public
void onResponse(Call call, Response response) throws IOException { } });

原始碼分析。


我們首先看下,OkHttpClient初始化做的事情

public OkHttpClient() {
    this(new Builder());
  }

  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.readTimeout = builder.readTimeout; this.writeTimeout = builder.writeTimeout; this.pingInterval = builder.pingInterval; } ... public Builder() { dispatcher = new Dispatcher(); ... connectTimeout = 10_000; readTimeout = 10_000; writeTimeout = 10_000; pingInterval = 0
; }


這裡我們看到,Okhttp是通過建造者模式初始化的。做的事情,主要是一些常用的配置。
(初始化排程器,快取策略,連線時間等等)

我們接著看Request的初始化

public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final RequestBody body;
  final Object tag;

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


我們可以看到,Request裡面,主要是通過建造者模式,配置進行網路請求的url,method,header等等內容。

接著看client.newCall(request)


上面做的事情都是配置網路請求的資訊。下面,這個呼叫會執行什麼呢。

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

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


我們發現這句程式碼非常簡單,就做了一件事。把上面我們構建好的Okhttp,Request傳給RealCall。
並初始化它。

最後看下執行call.enqueue(Callback)


我們看下最後是怎麼執行的呢

  @Override public void enqueue(Callback responseCallback) {
    //檢查是否已經執行了。
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    //把我們需要監聽的返回callback傳給AsyncCall,並初始化
    //呼叫我們okhttp建立的dispatcher的enqueue()方法。
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }


我們看下AysncCall這個類

 final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }


它的父類

public abstract class NamedRunnable implements Runnable {
  @Override public final void run() {
        ...
      execute();
        ...
  }

  protected abstract void execute();
}


我們發現AsyncCall是一個執行緒,並且父類實現了run()方法,並重新抽象了一個execute()方法,在run()裡面呼叫。讓AsyncCall來實現這個execute()方法。
如果呼叫這個執行緒的話,AsyncCall的execute()方法就會執行。

再看看 client.dispatcher().enqueue(AsyncCall)


看下這個裡面做了什麼操作。

public final class Dispatcher {
      private int maxRequests = 64;
  private int maxRequestsPerHost = 5;
  /** Ready async calls in the order they'll be run. */
    //這個是準備執行,非同步任務的佇列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
    //這個是正在執行非同步任務的佇列
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
    //這個是正在執行的同步任務的佇列
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

    獲取執行緒池
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
        //核心執行緒數為9,最大執行緒數Integer.MAX_VALUE,保留時間60秒
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
    ...

  synchronized void enqueue(AsyncCall call) {
    //判斷正在執行非同步任務的佇列數量是不是已經達到最大值了
    //如果沒有到最大值,並且host數量小於5。
    //我們就把這個執行緒放到正在執行的佇列裡,並執行它
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
        //新增
      runningAsyncCalls.add(call);
        //執行
      executorService().execute(call);
    } else {
        //否則,我們就放到準備執行的非同步任務佇列裡
      readyAsyncCalls.add(call);
    }
  }
}


到這裡,我們發現它確實就是一個排程器。
我們假設可以執行。我們看下AsyncCall的execute()方法,都做了什麼

AsyncCall的execute()方法

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
        注:1
        Response response = getResponseWithInterceptorChain();
        //如果沒有取消的話,就呼叫callback的onResponse,否則就呼叫onFailure。
        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 {
        //注:2
        client.dispatcher().finished(this);
      }
    }
  }


這裡,我們先不管注:1注:2。這就不管成功還是失敗,就把資料返回給了我們的callback。

接著,先看下注:2。它是在finally裡面執行的。所以執行完後,不管有沒有異常,這個方法總會執行的,我們先看下這個。

client.dispatcher().finished(this)

 /** Used by {@code AsyncCall#run} to signal completion. */
  void finished(AsyncCall call) {
    //呼叫過載方法,第三個引數為true
    finished(runningAsyncCalls, call, true);
  }

  private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    //同步
    synchronized (this) {
        //這裡把我們執行完的call移除了
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
        //呼叫了promoteCalls()方法
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }


···
private void promoteCalls() {
    //再來判斷是否,正在執行的佇列大於,最大的請求佇列。如果還大於就返回
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    //如果等待的佇列是空的,也返回
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
    //遍歷等待的佇列
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();
        //如果執行的佇列Host不大於最大的host。
        //把這個準備的任務,從等待佇列移除,放到正在執行的佇列,並立即執行。
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }
        //直到達到了最大的請求數量,就返回
      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }


這裡,我們就看完了一個任務完成後,做的事情。
1,移除完成的任務
2,判斷正在執行的佇列,是否還大於最大的請求數。
3,如果大於就返回,如果不大於就從等待的佇列裡面去取任務並執行,直到達到了,最大的請求數。

現在,我們就差分析,是怎麼返回的Response的了。接下來,我們就看下它是怎麼執行的。

Response response = getResponseWithInterceptorChain();

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));
    if (!forWebSocket) {
        //我們自己設定的網路攔截器
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));
    //初始化一個RealInterceptorChain跟Request,把攔截器都傳進去
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    //呼叫proceed()方法
    return chain.proceed(originalRequest);
  }


這裡也非常簡單,把我們自己設定的攔截器和它自身的,都放到集合裡。跟Request一塊傳給RealInterceptorChain。並呼叫proceed()方法。

我們再進去看看proceed犯法

RealInterceptorChain.proceed(originalRequest);

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

    calls++;
    ...

    // Call the next interceptor in the chain.
    //初始化,角標+1,取出interceptor呼叫intercept方法
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);
    Interceptor interceptor = interceptors.get(index);
    //並把下一個RealInterceptorChain穿進去,index+1
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    return response;
  }


這裡就是建立下一個攔截器。
呼叫當前攔截器的intercept(next)方法,把下一個攔截器傳進去。

  • 我們自己的interceptor
  • retryAndFollowUpInterceptor
  • BridgeInterceptor
  • CacheInterceptor
  • ConnectInterceptor
  • NetworkInterceptors
  • 我們自己的networkInterceptors
  • CallServerInterceptor

我們看下攔截器是怎麼傳下去的

RetryAndFollowUpInterceptor.java
@Override public Response intercept(Chain chain) throws IOException {
    ...
     response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
    ...
}
BridgeInterceptor.java
  @Override public Response intercept(Chain chain) throws IOException {
        Response networkResponse = chain.proceed(requestBuilder.build());
    }
...


都是呼叫下一個構造的chain的proceed方法。
然後,在裡面構造下一個chain,執行intercept方法。

* 攔截器的作用:*

  • 對當前的request請求做處理(新增/刪除頭資訊等)。
  • 呼叫下一個攔截器。
  • 對響應的Response結果,做處理(寫入快取等),並返回給上一個攔截器。

呼叫完之後,響應Response。整個流程完成。

下一次,看下攔截器都做了什麼功能呢。