okhttp3源码解析-全体流程

前语

最近有时间看了看okhttp的源码,之前基本是通过别人的书本、博客去学习源码的,这次是彻底自己去看、去探索,还挺有意思的,这儿略微记录下。

okhttp3的首要流程

要研讨一个凌乱的源码结构,首先要搞定它的首要流程,知道个大约,再去研讨细节,这儿从网上找了一张图片,我觉得把okhttp的流程画的很清楚了: ![pic](img-blog.csdnimg.cn/ba1a19fd586… =300x) 然后我们再看下okhttp的一般调用状况:

// 1,创建OkHttpClient
OkHttpClient httpClient = new OkHttpClient.Builder().build();
// 2,创建Request
Request request = new Request.Builder().url("xxx").build();
// 3,创建Call
Call call = httpClient.newCall(request);
// 4,运用call主张央求:
// 同步运用
Response response = call.execute();
// 异步央求
call.enqueue(callback)

下面我们就根据这四个步骤去查看源码,理解其间的规划思想。

源码分析

创建OkHttpClient

制作者方法,规划方法了,我这儿不讲,只讲在OkHttpClient的运用。这儿实践就三部分内容:

  1. 参数及setter和getter函数
  2. 结构函数,用于创建参数的默认值
  3. build函数,调用OkHttpClient结构传入builder创建实例 这儿就可以完结只设置部分参数创建OkHttpClient实例的功用。

创建Request

这儿也运用了制作者方法,和上面相似,需求留心的是request是不行修正的,看下其阐明:

An HTTP request. Instances of this class are immutable if their body is null or itself immutable.

创建Call

前面创建了OkHttpClient和Request的实例,都还没有到中心代码,接下来是实践内容:

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

这儿直接调用RealCall创建了一个RealCall方针,代码进入了RealCall内部的static方法,这儿做了两件事:

  1. 调用RealCall的构建方法创建了一个RealCall方针
  2. 向OkHttpClient中传入了一个eventListener
  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;
  }

RealCall的构建方法:

  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
    this.timeout = new AsyncTimeout() {
      @Override protected void timedOut() {
        cancel();
      }
    };
    this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
  }

这儿向RealCall内设置了传入的参数,并创建了retryAndFollowUpInterceptor和timeout方针。retryAndFollowUpInterceptor这个拦截器比较重要,需求留心下它是在这儿创建的,后边会详解这个拦截器。关于timeout这个特色,我没有花时间去研讨,不过可以供给一个别人写的很好的博文,有爱好的读者可以看下:

/post/696246…

eventListener工作监听

eventListener尽管和央求的主流程没什么太大关系,但是这个也是OkHttp一个强壮的功用,它会在每个功用调用的时分提示工作发生的状况,可以查看下其间的方法:

okhttp3源码解析(1)-全体流程

运用call主张央求

前面通过三步操作得到了一个RealCall的实例,终究一步就是通过RealCall去主张同步或异步央求,下面我们先看同步央求,再去看异步央求,尽管异步央求麻烦了一些,但是终究都会汇聚在getResponseWithInterceptorChain方法。

同步央求

同步央求通过调用RealCall的execute方法得到Response,这儿运用executed验证了央求是否已实行,并设置了超时计时、工作调用等。

  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    timeout.enter();
    eventListener.callStart(this);
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      e = timeoutExit(e);
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }

这儿我们偏重留心try-catch内部的内容,这儿又做了两件事,一是调用OkHttpClient内的dispatcher实行当时RealCall,二是通过getResponseWithInterceptorChain获取response。 点开dispatcher的executed方法,里边只是将RealCall方针保存到一个数组里去了:

  /** Used by {@code Call#execute} to signal it is in-flight. */
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

关于Dispatcher我们后边再讲,先看下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));
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
    return chain.proceed(originalRequest);
  }

这儿就通过一系列的拦截器,通过责任链的方法处理,终究得到了Response,看起来很简单,我们暂时就以为这儿就拿到了Response,责任链内的代码后边博文研讨,下面先看异步央求。

异步央求

异步央求通过OkHttpClient的enqueue方法,传入responseCallback得到成果,代码如下:

  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

这儿和同步央求的execute相似,但是终究是通过调用dispatcher的enqueue完结调用,传入了封装responseCallback的AsyncCall方针,下面我们看下AsyncCall方针:

final class AsyncCall extends NamedRunnable {
    // 省掉部分代码
    /**
     * Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up
     * if the executor has been shut down by reporting the call as failed.
     */
    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        eventListener.callFailed(RealCall.this, ioException);
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }
    @Override protected void execute() {
      boolean signalledCallback = false;
      timeout.enter();
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        e = timeoutExit(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 {
        client.dispatcher().finished(this);
      }
    }
  }

这儿省掉了部分代码,我们偏重重视下executeOn和execute两个方法。实践上AsyncCall就是一个Runnable,它的run方法里边会实行execute方法。 再来看executeOn方法,除掉一些反常处理,实践就是调用了executorService的execute方法实行AsyncCall这个Runnable,这儿的目的就是供给一个线程池来实行AsyncCall的execute()代码。 继续看execute方法,再次忽略反常处理,实践就是调用了getResponseWithInterceptorChain方法获得response,只是这个execute方法实行在指定线程池,也就是说完结了异步实行。

client.dispatcher().enqueue(new AsyncCall(responseCallback));

这儿分析了AsyncCall这个类对responseCallback的封装,回过头来,我们再看下dispatcher的enqueue方法做了什么:

  void enqueue(AsyncCall call) {
    synchronized (this) {
      readyAsyncCalls.add(call);
    }
    promoteAndExecute();
  }

这儿也比较简单,异步嘛,先加锁,再把AsyncCall存入数组里边,紧接着调用了promoteAndExecute()来推进代码实行。这儿我们就在下面的Dispatcher中偏重分析了。

Dispatcher

前面讲到的同步央求和异步央求,都是通过dispatcher去实行,再通过getResponseWithInterceptorChain拿到Response的,下面我们就来研讨下这个Dispatcher,忽略部分功用,我们偏重看下下面几个内容。

数据域
  private @Nullable ExecutorService executorService;
  /** 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<>();

这儿忽略了最大央求数、同域名最大连接数和无任务时处理的idleCallback。executorService通过调用executorService()方法得到,是异步实行的线程池。 三个Deque对应着工作的同步队伍、准备的异步队伍、工作的异步队伍,留心工作的队伍包含了取消但未结束的Call,其间同步队伍保存的是RealCall,而异步队伍保存的是AsyncCall(Runnable)。

方法域

方法域我们偏重介绍下一下promoteAndExecute和finished方法,前面现已讲到同步央求和异步央求调用enqueue和executed只是将任务放到队伍中去,异步央求会再实行下promoteAndExecute方法,下面具体介绍:

  /**
   * Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs
   * them on the executor service. Must not be called with synchronization because executing calls
   * can call into user code.
   *
   * @return true if the dispatcher is currently running calls.
   */
  private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));
    // 从ready列表中拿出call存到实队伍表
    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
        i.remove();
        executableCalls.add(asyncCall);
        runningAsyncCalls.add(asyncCall);
      }
      isRunning = runningCallsCount() > 0;
    }
    // 调度实行
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());
    }
    return isRunning;
  }

promoteAndExecute就分两步,先将异步任务从ready队伍中取出,并放到running的队伍中,第二步再实行其间的任务,并不是很凌乱,executeOn实行就到AsyncCall的execute方法了。

  /** Used by {@code AsyncCall#run} to signal completion. */
  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call);
  }
  /** Used by {@code Call#execute} to signal completion. */
  void finished(RealCall call) {
    finished(runningSyncCalls, call);
  }
  private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }
    boolean isRunning = promoteAndExecute();
    if (!isRunning && idleCallback != null) {
      idleCallback.run();
    }
  }

finished方法通过泛型的方法完结了对同步任务和异步任务的结束,这儿还工作了下idleCallback。

运用call主张央求——小结

至此,同步央求和异步央求的全体流程就差不多结束了,逻辑进入到了几个拦截器的责任链中,我们下篇博文分析,这儿略微小结下. 同步央求和异步央求,都通过了两步,一是存入dispatcher的队伍中,二是通过getResponseWithInterceptorChain拿到成果,异步央求会在dispatcher中通过线程池实行,并将getResponseWithInterceptorChain方法带到异步线程。

下一篇

okhttp3源码解析(2)-拦截器 I