okhttp源码解析1--同步|异步请求流程

Okhttpclient流程图.png

基础分析(深入分析(dispatcher、拦截器等)流程较长且更复杂,后面会单独介绍)

1. 基本请求流程


//1.创建okhttpclient和Request对象,并设置一些配置

OkHttpClient okHttpClient =new OkHttpClient().newBuilder().connectTimeout(5,TimeUnit.SECONDS).build();

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

//2.将request封装成call对象
Call call = okHttpClient.newCall(request);

try {

  //3.调用Call的execute()发送同步请求

    Response response = call.execute();

  //4.call执行异步请求
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    
                }

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

                }
            });
}catch (IOException e) {

e.printStackTrace();

}

1.1 创建okhttpclient和Request对象,并进行初始化配置:
  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;
    }

使用建造者进行创建,这种模式适合于当需要初始化很多内容的时候。
注意其中dispatcher分发器,ConnectionPool链接池(可将我们的一个个请求理解为链接,链接池就是来管理这些链接的)主要作用:1.当请求的url是相同的时候可选择复用 2.设置链接策略。 后面会详细介绍


/**
 * Policy on when async requests are executed.
 *
 * 

Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your * own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number * of calls concurrently. */ public final class Dispatcher { private int maxRequests = 64; private int maxRequestsPerHost = 5; private @Nullable Runnable idleCallback; /** Executes calls. Created lazily. */ private @Nullable ExecutorService executorService; /** Ready async calls in the order they'll be run. */ private final Deque readyAsyncCalls = new ArrayDeque<>(); /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque runningAsyncCalls = new ArrayDeque<>(); /** Running synchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque runningSyncCalls = new ArrayDeque<>(); public Dispatcher(ExecutorService executorService) { this.executorService = executorService; } public Dispatcher() { } public synchronized ExecutorService executorService() { if (executorService == null) { executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false)); } return executorService; }

dispatcher内部维护着网络请求的线程池,分别是readyAsyncCalls(等待中的同步请求队列)、runningAsyncCalls(请求中的异步请求队列)、runningSyncCalls(请求中的 同步请求队列)。它的代码量不多却是okhttp的核心之一。

1.2 将request封装成call对象
/**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }

newcall方法实际创建了call接口的实现类RealCall:


  RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();

    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);

    // TODO(jwilson): this is unsafe publication and not threadsafe.
    this.eventListener = eventListenerFactory.create(this);
  }

这里的OkHttpClient,requst引用过来了

1.3 调用Call的execute()发送同步请求
  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

getResponseWithInterceptorChain()这里实际上是调用了拦截器链,并通过拦截器一层层的递归,最终得到了请求返回Response,它的内容比较多具体在okhttp源码解析--拦截器中进行分析

executed判断同一个http请求只能执行一次,否者直接抛出异常

client.dispatcher().executed(this);

直接调用dispatcherexecuted方法

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

添加到dispatcherrunningSyncCalls同步请求队列中,通过getResponseWithInterceptorChain()拦截器链获得Request并在finally中释放当前请求。dispatcher中被调用的finished方法:

 /** Used by {@code AsyncCall#run} to signal completion. */
  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }

  /** Used by {@code Call#execute} to signal completion. */
  void finished(RealCall call) {
    finished(runningSyncCalls, call, false);
  }

  private  void finished(Deque 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();
    }
  }

在队列中移除请求,到此同步请求完毕。

1.4 异步请求enqueue

异步请求与同步请求只在最后一步调用的方法不同

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

首先和execute方法一样判断是否是第一次请求,captureCallStackTrace()获取网络请求的一些堆栈信息.最后一步才是真正的调用了dispatcher的上了同步锁enqueue方法,AsyncCall继承NamedRunnable就是一个runable

/**
 * Runnable implementation which always sets its thread name.
 */
public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

Dispatcher中的enqueue

public final class Dispatcher {
  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;

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

首先判断异步执行中的队列是否已达到最大请求数量64&&线程数是否已到5条,没有则添加到runningAsyncCalls队列并通过线程池执行请求,否者添加到readyAsyncCalls等待队列.

Dispatcher中的线程池

 public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

这里核心线程数是0(核心线程设置为0的作用在于,当线程池没有核心线程空闲一段时间后会销毁所有的线程),最大线程数量是最大值(因为上面已经设置了maxRequests(64)了,60代表线程执行完毕后60秒会被销毁,所有不用担心会造成极端请求的情况)。最后 executorService().execute(call)就调用了当前线程池中子线程的run方法,也就是上图的NamedRunnable中的run(),其中NamedRunnable的核心抽象方法execute()在它的实现类AsyncCall中具体实现:

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();
        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 {
        client.dispatcher().finished(this);
      }
    }
  }

通过getResponseWithInterceptorChain()拦截链获取到了请求返回Response
retryAndFollowUpInterceptor.isCanceled()判断请求是否取消,
取消就调用 responseCallbackonFailure(...)失败方法,
否则responseCallbackonResponse(...)返回数据。这样一个异步请求就完成了。

注意finally中的finished,通过它dispatcher维护了队列,线程池执行下一个网络请求,具体会在下一篇进行介绍

你可能感兴趣的:(okhttp源码解析1--同步|异步请求流程)