深刻OKHttp源码分析(一)----同步和异步请求流程和源码分析

好久没有写过博客了,一直认为本身的技术实力不够,怕写了技术博客产生错误,误导了你们,让你们在错误的方向越走越远,不能解决本身的问题,前段时间看了某大佬的关于写做的分享,我决定从今天开始将本身在Android开发路上学习和解决问题的历程记录下来,若是博客中有错误的地方,也欢迎你们指正,咱们共同进步共同窗习。今天从OKhttp的源码分析开始! ###OKhttp框架流程 基本的执行流程以下: OKhttpClient->Request->RealCall->Dispatcher->interceptors(RetryAndFollow->Bridge->Cache->Connect->CallServer)web

名词解释: #####OkHttpClient: 按照类文件中的说明就是发送HTTP请求和读取响应的实例。也是Call的生产工厂 #####Request : HTTP请求 #####RealCall :真正的Call对象。 #####Dispatcher : 任务调度器 #####interceptors : 拦截器,其中包含RetryAndFollow、Bridge、Cache、Connect、CallServer,拦截器也能够自定义bash

####OkHttp同步请求流程和源码分析cookie

OkHttpClient client=new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();

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

        Call call = client.newCall(request);

        try {
            Response response = call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
复制代码

首先咱们来看下OkHttpClient实例的建立,OkHttpClient实例是经过建立者模式来建立的,咱们来看下其源码框架

public Builder() {
      dispatcher = new Dispatcher();//这里建立了OKhttp的任务调度器对象
      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;
    }
复制代码

经过上面的代码来看,这个方法里面主要是基本的赋值操做和任务调度器对象和链接池对象的建立,咱们继续往下看build方法异步

public OkHttpClient build() {
      return new OkHttpClient(this);
    }
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.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;
    ···//篇幅缘由,这里就将剩下的代码注释啦。
  }
复制代码

在build方法中直接返回了新建立的OkHttpClient对象,将Builder对象传入OkHttpClient中,并在OkHttpClient的构造方法中进行赋值操做,此时,OkHttpClient的实例对象建立完成。socket

接着咱们看下请求对象Request的建立过程:async

Request request=new Request.Builder().url("http://www.baidu.com").build();
复制代码

也和OkHttpClient的建立过程同样,也是使用了建立者模式,咱们来看下Builder方法ide

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

在这里咱们能够看到,默认状况下,请求方式为GET方式,而后建立了header对象,用来存储HTTP的请求头数据,url方法就是设置url地址的,咱们就不跳进去看代码了,咱们看下build方法函数

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;
  }
复制代码

在build方法中,进行了url的判空操做,而后将Builder对象传入Request类的构造函数,返回新建立的Request对象 在Request的构造函数中,只是进行简单的赋值操做。此时Request对象也已经建立完成。源码分析

接着进行第三步了,建立Call对象

Call call = client.newCall(request);
复制代码

咱们点击newCall方法进去看看Call对象是具体如何建立的

/**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
复制代码

咱们能够看到,里面很简单,其实Call对象的真正建立是在RealCall的newRealCall方法里的,咱们进去看看

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;
  }
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }
复制代码

在newRealCall方法中咱们看到,RealCall的建立是经过构造函数建立的,咱们点进来继续看,里面只是一些简单的赋值操做,可是,请注意,最后一页是咱们在前面简介过的重试拦截器RetryAndFollowUpInterceptor的建立。这里咱们先不详细的介绍,后面再详细讲解。 在newRealCall方法中的最后一行是建立Call对象的事件监听对象。 到此为止,Call对象建立成功。 咱们继续往下看,最后一步,

Response response = call.execute();
复制代码

调用call的execute()方法,获得咱们想要的response对象,咱们进入到execute方法中看看里面是如何获得咱们要的response对象的。

@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);
    }
  }
复制代码

咱们直接来看关键代码,client.dispatcher().executed(this);,咱们看下dispatcher方法,

public Dispatcher dispatcher() {
    return dispatcher;
  }
复制代码

能够看到,这里直接返回了以前在构造器中建立的dispatcher对象,咱们接着看execute方法,

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

这个runningSynCalls是什么鬼呢,咱们看下定义位置

/** 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<>(); 复制代码

能够看到,这个是一个存放尚未执行完毕的同步任务的队列,咱们还看到了另外两个队列readyAsyncCalls、runningAsyncCalls,一个是待执行的异步任务的队列,一个是正在执行的异步任务的队列。这两个实例咱们在后面的异步请求中会用到,这里先跳过。 咱们回头看下executed方法,这里只是将Call对象添加到同步任务的执行队列中。 回到前面的代码中,咱们接着往下看,

Response result = getResponseWithInterceptorChain();
复制代码

原来真正获得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));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }
复制代码

return语句以前的代码都是建立拦截器链的操做,拦截器链建立完成后,经过拦截器链的proceed方法获得response对象,咱们继续跟进

@Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }
复制代码

咱们能够看到里面又调用了另外一个重载的proceed方法,咱们跳过去看下,

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

    calls++;
    ···//省略部分代码
    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    ···//为了简化篇幅,将后面一些判断代码进行省略
    return response;
  }
复制代码

咱们能够看到中间的代码,这部分代码就是获得拦截器链中的下一个拦截器,而后进行该拦截器的intercept(next)方法操做,在这个方法中,会继续调用拦截器链中的下一个拦截器的intercept(next)方法调用,最后执行到CallServerInterceptor拦截器,从而获取真正的response对象,而后一层层的返回,每返回一层,在当前层的拦截器中进行包装处理,最后返回到这里,再进行返回,从而获得咱们要的response对象。拦截器链中的详细执行流程咱们后面再详细讲解。

经过上面的代码分析,咱们就已经分析完了同步请求的执行流程。下面咱们继续看下异步请求流程的源码分析。 ####OkHttp异步请求流程和源码分析 咱们先来看下如何来执行异步请求

OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();

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

        Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

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

            }
        });
复制代码

咱们能够看到,前面三行代码是和同步请求一致,咱们重点来看call的enqueue方法。上面咱们讲过,call对象的真正实现是RealCall,那咱们就看RealCall中enqueue方法的实现

@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));
  }
复制代码

最后一行,仍是OkHttpClient对象获取了任务调度器来执行enqueue方法,并将咱们传递进来的Callback对象封装成AsyncCall对象,咱们看下Dispatcher中的enqueue方法:

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

能够看到,首先进行判断,若是正在运行的异步任务数量小于指定的数量(64),就将AsyncCall对象添加到正在运行的异步任务队列中,并加入线程池中执行任务,不然就加入到等待运行的异步任务队列中去。若是线程池中线程开始运行了,线程池中的执行对象确定是一个线程,那就确定要有run方法的,那么咱们就来看下AsyncCall究竟是个什么东东。

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }
	······//省略部分代码
  }
复制代码

上面代码中咱们能够看到,AsyncCall继承了NamedRunnable,咱们继续看NamedRunnable是什么,

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();
}
复制代码

能够看到,原来NamedRunnable实现了Runnable接口,确定要执行run方法,那就看下NamedRunnable的run方法,其中最重要的就是execute();这一句了,咱们看下execute()方法,咦,是个抽象方法,这个方法是给其子类来实现的,那么咱们看下刚刚实现了NamedRunnable类的子类AsyncCall中的executed方法,

@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 {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
复制代码

咱们能够看到熟悉的代码,熟悉的味道,······,额,咱们看下这一行

Response response = getResponseWithInterceptorChain();
复制代码

是否是似曾相识呢,对的,在前面的同步执行流程的源码分析中咱们已经见过这个代码了,若是你不记得了,就往前面翻一翻,这里就再也不讲解啦。经过这一句,咱们获得了咱们想要的response对象,那么咱们看下下面的代码是作什么的 try···catch代码块中是判断和对callback方法的调用,咱们忽略它,来看下finally中的代码,咱们知道,finally中的代码是必定会执行到的,咱们看下finished方法

void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }
  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();
    }
  }
复制代码

finished方法调用了重载的另外一个finished方法,咱们看下,在finished方法中,首先将刚刚执行完的call对象进行移除队列,而后咱们看这行代码

if (promoteCalls) promoteCalls();
复制代码

咱们看下promoteCalls()方法

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

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }
复制代码

头两行代码是判断正在执行的任务队列中的任务数量若是大于或等于指定的最大任务数就返回,或者正在等待的任务数为0也返回,咱们来看下for循环中的代码,这里是对等待的任务队列进行遍历,首先取出一个任务,判断是否符合运行条件,若是符合,就将其从等待队列中移除,添加到运行队列中去,并加入线程池执行,最后一行,若是正在运行的任务数量大于等于最大指定任务数,就跳出for循环,咱们能够看到,这个promoteCalls方法的做用就是判断正在运行的任务数量,若是数量小于指定的任务数,就从等待的任务队列中取出,添加到正在运行的任务队列中,并加入线程池中运行,那么这里就又能够回到前面分析过的代码,那咱们就继续回到前面的finished方法中去,继续往下看,

runningCallsCount = runningCallsCount();
复制代码

咱们来看下这行代码

public synchronized int runningCallsCount() {
    return runningAsyncCalls.size() + runningSyncCalls.size();
  }
复制代码

很简单,只是从新计算正在运行的任务数量,如今咱们回过头来继续看finished方法中的最后一部分代码

if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
复制代码

这里是判断若是正在执行的任务数量为0,而且空闲回收线程不为null,就执行空闲回收线程的run方法进行回收操做。

好了,到此为止,咱们就已经分析完了同步和异步执行流程,下一篇咱们来分析okhttp的任务调度核心类Dispatcher

相关文章
相关标签/搜索