(Android) OkHttp3.10 源码学习笔记 1 同步请求分析

OkHttp的请求分为同步请求和异步请求,下面我们先来分析同步请求的执行流程。

首先,看一下OkHttp执行同步请求的简单示例:

OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url("http://baidu.com")
                .build();

        Response response;
        try {
            response = client.newCall(request).execute();
            Log.d(TAG, response.body() != null ? response.body().toString() : null);
        } catch (IOException e) {
            e.printStackTrace();
        }

第一步,我们new了一个OkHttpClient,使用了默认的构造函数。

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

这里返回了一个new Builder(). 这个大家应该很熟悉,一个Builder模式的写法。跟进源码部分,可以看到它主要做了一些成员变量的初始化工作。比如Dispatcher,是请求分发器,连接池管理的connectionPool, 我们后面将重点分析, 以及一些timeout的设置等。

public Builder() {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;
    }

第二步,下面我们看Request的初始化过程

Request request = new Request.Builder()
                .url("http://baidu.com")
                .build();

跟进Builder()方法,主要做了两件简单的事,默认为GET方式,初始化了Header,保存头部信息,传入的url String构造HttpUrl对象。

 public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }

再看Build()方法,直接用之前的Builder对象,构造一个request。

public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }
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;
  }
第三步,通过下面的方法,得到response
response = client.newCall(request).execute();

我们看看call的创建过程

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

Call是一个接口,RealCall是Call的具体实现。这边直接使用RealCall类的静态方法newRealCall创建了一个RealCall对象

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对象,赋值了一个listener。继续看RealCall的构造方法

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

可以看出,RealCall持有了之前构造的client request对象,赋值了一个重定向拦截器,关于拦截器,后面也会具体分析。

最后,执行call.excute()方法,继续看具体实现类RealCall

@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();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }

首先,判断了excuted标志位是否为true,因为同一个请求只能执行一次,如果已经执行了 就抛出异常,没执行过,就把标志位置为true。

然后,捕捉call堆栈,并且执行了listener的callStart方法,看一下。

/**
   * Invoked as soon as a call is enqueued or executed by a client. In case of thread or stream
   * limits, this call may be executed well before processing the request is able to begin.
   *
   * <p>This will be invoked only once for a single {@link Call}. Retries of different routes
   * or redirects will be handled within the boundaries of a single callStart and {@link
   * #callEnd}/{@link #callFailed} pair.
   */
  public void callStart(Call call) {
  }

注释上可以看出,每次执行call的enqueued或execute方法时,就会开启这个listener。往下看核心代码

 try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
首先,执行了dispatcher的exexuted方法,dispatcher是OkHttp的请求分发器,对于同步请求,executed也比较简单,只是把call放入了running这个队列
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

其实Dispatcher的作用,就是维持call请求发给他的状态,然后内部维护了一个线程池,用于执行网络请求。call在执行的过程中,通过dispatcher这个分发器类,把任务推到执行队列当中,进行操作,操作完成,再执行等待队列的任务。Dispatcher是OkHttp的核心之一,后面会具体分析。



接下来我们继续代码,同步请求队列的定义,下面代码中 的第三个。上面两个,一个是异步的就绪队列,一个是异步的执行队列。

  /** 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<>();

执行完dispatcher.executed()方法后,会通过getResponseWithInterceptorChain()方法得到response。这个其实是一个拦截器链方法,后面也会具体分析。

最后我们看一下finally方法,他会在请求结束后执行finished方法

  void finished(RealCall call) {
    finished(runningSyncCalls, call, false);
  }

  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();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

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

可以看出,把我们正在执行的同步请求传入,从当前队列移除同步请求。这边主要第三个参数我们传入的是false,这里是走不到promoteCalls()的,但异步请求会走到这里,到时再分析。然后,计算了目前还在运行的请求。最后两行有一个判断,如果runningCallsCount为0且idleCallback不为null时,运行了idleCallback。


最后,我们总结一下同步请求

1.创建一个OkHttpClient对象

2.构建一个request对象,通过OkHttpClient和Request对象,构建出Call对象

3.执行call的execute方法。




猜你喜欢

转载自blog.csdn.net/zhouy1989/article/details/80530406