掌握Okhttp (2) : OKhttp整体流程分析

本文,将对Okhttp整体流程进行分析.
本文若无特殊说明,采用的okhttp版本为 3.10.0

一.OkHttpClient分析

创建 OkHttpClient实例的两种方式:

代码片1
 OkHttpClient okHttpClient = new OkHttpClient();

 OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

我们先研究第一种构造方式,也是默认的方式,我们点击OkHttpClient方法进去:

OkHttpClient.class

代码片2
 public OkHttpClient() {
    
    
    this(new Builder());
 }

发现是一个类构造方法,this其实就是指的是OkHttpClient,也就是如下方法:

OkHttpClient.class

代码片3
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;
    //删除多行代码
  }

然后顺理成章的看一下new Builder() 方法

OkHttpClient.class

代码片4
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;
 }

上述代码是做一些初始化配置.

现在来看另一个种构造方式:

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

点开build() 方法,代码如下:

OkHttpClient.class

代码片5
 public OkHttpClient build() {
    
    
      return new OkHttpClient(this);
 }

这里需要我们注意的是Builder 它是静态内部类.

上面讲到了OkHttpClient的两种构造方式,通过查看源码,两种方式的配置是相同的,下面具体看一下到底配置了什么(即代码片4):
具体的配置内容,在下面代码中已经注释.

OkHttpClient.class

代码片6
public Builder() {
    
    
      dispatcher = new Dispatcher();   //调度器,执行异步请求时的策略   
      protocols = DEFAULT_PROTOCOLS;   //OKHTTP实现的协议LIST
      connectionSpecs = DEFAULT_CONNECTION_SPECS;   //TLS版本与连接协议
      eventListenerFactory = EventListener.factory(EventListener.NONE);    //监听器
      proxySelector = ProxySelector.getDefault();    //代理选择器
      cookieJar = CookieJar.NO_COOKIES;     //cookie
      socketFactory = SocketFactory.getDefault();    //socket 工厂
      hostnameVerifier = OkHostnameVerifier.INSTANCE;    //主机name验证
      certificatePinner = CertificatePinner.DEFAULT;    
      proxyAuthenticator = Authenticator.NONE;     //代理验证
      authenticator = Authenticator.NONE;   //验证
      connectionPool = new ConnectionPool();    //连接池
      dns = Dns.SYSTEM;     //dns域名
      followSslRedirects = true;     //安全套接层重定向
      followRedirects = true;    //本地重定向
      retryOnConnectionFailure = true; //错误重连
      connectTimeout = 10_000;   //connect超时
      readTimeout = 10_000;   //read超时
      writeTimeout = 10_000;    //write超时
      pingInterval = 0;   //ping超时
 }

二.Request初始化

当我们构建完OkHttpClient对象,需要构造Request对象,构造方式如下:

1.Get请求:

 Request request = new Request.Builder()
        .url("https://www.wanandroid.com/article/list/1/json")
        .get()//默认就是GET请求,可以不写
        .build();

2.Post请求

POST提交表单请求,这时就需要声明一个RequestBody对象了

RequestBody requestBody = new FormBody.Builder()
        .add("username", "weibuzudao")
        .add("password", "123456")
        .build();
        
Request request = new Request.Builder()
       .url("https://www.wanandroid.com/user/login")
       .post(requestBody)
       .build();

看到上面代码是不是很熟悉?和OkHttpClient很相似, 没错 Request 的构建也是Builder模式!

我们点击Request源码进去,果然 其中有静态的Builder内部类:

Request.class

代码片7
public static class Builder {
    
    
   HttpUrl url;
   String method;
   Headers.Builder headers;
   RequestBody body;

   //这里配置默认的参数
   public Builder() {
    
    
      this.method = "GET";    //默认是GET请求
      this.headers = new Headers.Builder();
   }
   
 //这里通过另外一个Request配置参数
    Builder(Request request) {
    
    
      this.url = request.url;
      this.method = request.method;
      //...
    }

   //省略部分代码
   // 配置完参数后,通过Builder的参数创建一个Request
   public Request build() {
    
    
      if (url == null) throw new IllegalStateException("url == null");
    return new Request(this);
   }
}

从代码看到了 如果没有声明,默认是Get请求 this.method = "GET" ,至于url等字段需要我们自己去配置:

HttpUrl

请求访问的url ,可以传StringURL 具体方法如下:

Request.class

代码片8
  public Builder url(HttpUrl url) {
    
    
      if (url == null) throw new NullPointerException("url == null");
      this.url = url;
      return this;
   }

    /**
     * Sets the URL target of this request.
     *
     * @throws IllegalArgumentException if {@code url} is not a valid HTTP or HTTPS URL. Avoid this
     * exception by calling {@link HttpUrl#parse}; it returns null for invalid URLs.
     */
    public Builder url(String url) {
    
    
      if (url == null) throw new NullPointerException("url == null");

      // Silently replace web socket URLs with HTTP URLs.
      if (url.regionMatches(true, 0, "ws:", 0, 3)) {
    
    
        url = "http:" + url.substring(3);
      } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
    
    
        url = "https:" + url.substring(4);
      }

      HttpUrl parsed = HttpUrl.parse(url);
      if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
      return url(parsed);
    }

    /**
     * Sets the URL target of this request.
     *
     * @throws IllegalArgumentException if the scheme of {@code url} is not {@code http} or {@code
     * https}.
     */
    public Builder url(URL url) {
    
    
      if (url == null) throw new NullPointerException("url == null");
      HttpUrl parsed = HttpUrl.get(url);
      if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
      return url(parsed);
    }

method

请求类型 String method,支持多种请求类型

Request.class

代码片9
 public Builder get() {
    
    
      return method("GET", null);
    }

    public Builder head() {
    
    
      return method("HEAD", null);
    }

    public Builder post(RequestBody body) {
    
    
      return method("POST", body);
    }

    public Builder delete(@Nullable RequestBody body) {
    
    
      return method("DELETE", body);
    }

    public Builder delete() {
    
    
      return delete(Util.EMPTY_REQUEST);
    }

    public Builder put(RequestBody body) {
    
    
      return method("PUT", body);
    }

    public Builder patch(RequestBody body) {
    
    
      return method("PATCH", body);
    }

Headers

Headers.Builder Http消息的头字段
前面看到了, 我们在初始化Request的时候 同时初始化了headers, this.headers = new Headers.Builder()(代码片7第9行代码)

可以通过 header addHeader removeHeader headers 方法做一些操作

Request.class

代码片10

   public Builder header(String name, String value) {
    
    
      headers.set(name, value);
      return this;
    }

   
    public Builder addHeader(String name, String value) {
    
    
      headers.add(name, value);
      return this;
    }

    public Builder removeHeader(String name) {
    
    
      headers.removeAll(name);
      return this;
    }

    public Builder headers(Headers headers) {
    
    
      this.headers = headers.newBuilder();
      return this;
    }

body

RequestBody类型,它是抽象类, 有些请求需要我们传入body实例 ,我们在通过源码来看一下:

如果是GET请求,body对象传的是null
Gethead方法不能传body对象 ,其他method是可以的

   public Builder get() {
    
    
      return method("GET", null);
    }

    public Builder head() {
    
    
      return method("HEAD", null);
    }

如果是POST delete put patch请求,就需要我们去设定了:

   public Builder post(RequestBody body) {
    
    
      return method("POST", body);
    }

    public Builder delete(@Nullable RequestBody body) {
    
    
      return method("DELETE", body);
    }

    public Builder delete() {
    
    
      return delete(Util.EMPTY_REQUEST);
    }

    public Builder put(RequestBody body) {
    
    
      return method("PUT", body);
    }

    public Builder patch(RequestBody body) {
    
    
      return method("PATCH", body);
    }

RequestBody解析

首先我们看一下RequestBody如何初始化??拿提交表单举例:

       RequestBody requestBody = new FormBody.Builder()
                .add("username", "weibuzudao")
                .add("password", "123456")
                .build();
                
        Request request = new Request.Builder()
                .url("https://www.wanandroid.com/user/login")
                .post(requestBody)
                .build();

不出所料,也是Builder模式,而且RequestBody 是抽象类, FormBodyRequestBody的其中一种实现类 ,另一个实现类是MultipartBody.

public final class FormBody extends RequestBody {
    
    
public final class MultipartBody extends RequestBody {
    
    

RequestBody源码如下:

RequestBody.class

public abstract class RequestBody {
    
    
  /** Returns the Content-Type header for this body. */
  public abstract @Nullable MediaType contentType();

  /**
   * Returns the number of bytes that will be written to {@code sink} in a call to {@link #writeTo},
   * or -1 if that count is unknown.
   */
  public long contentLength() throws IOException {
    
    
    return -1;
  }

  /** Writes the content of this request to {@code sink}. */
  public abstract void writeTo(BufferedSink sink) throws IOException;

  /**
   * Returns a new request body that transmits {@code content}. If {@code contentType} is non-null
   * and lacks a charset, this will use UTF-8.
   */
  public static RequestBody create(@Nullable MediaType contentType, String content) {
    
    
    Charset charset = Util.UTF_8;
    if (contentType != null) {
    
    
      charset = contentType.charset();
      if (charset == null) {
    
    
        charset = Util.UTF_8;
        contentType = MediaType.parse(contentType + "; charset=utf-8");
      }
    }
    byte[] bytes = content.getBytes(charset);
    return create(contentType, bytes);
  }

  /** Returns a new request body that transmits {@code content}. */
  public static RequestBody create(
      final @Nullable MediaType contentType, final ByteString content) {
    
    
    return new RequestBody() {
    
    
      @Override public @Nullable MediaType contentType() {
    
    
        return contentType;
      }

      @Override public long contentLength() throws IOException {
    
    
        return content.size();
      }

      @Override public void writeTo(BufferedSink sink) throws IOException {
    
    
        sink.write(content);
      }
    };
  }

  /** Returns a new request body that transmits {@code content}. */
  public static RequestBody create(final @Nullable MediaType contentType, final byte[] content) {
    
    
    return create(contentType, content, 0, content.length);
  }

  /** Returns a new request body that transmits {@code content}. */
  public static RequestBody create(final @Nullable MediaType contentType, final byte[] content,
      final int offset, final int byteCount) {
    
    
    if (content == null) throw new NullPointerException("content == null");
    Util.checkOffsetAndCount(content.length, offset, byteCount);
    return new RequestBody() {
    
    
      @Override public @Nullable MediaType contentType() {
    
    
        return contentType;
      }

      @Override public long contentLength() {
    
    
        return byteCount;
      }

      @Override public void writeTo(BufferedSink sink) throws IOException {
    
    
        sink.write(content, offset, byteCount);
      }
    };
  }

  /** Returns a new request body that transmits the content of {@code file}. */
  public static RequestBody create(final @Nullable MediaType contentType, final File file) {
    
    
    if (file == null) throw new NullPointerException("content == null");

    return new RequestBody() {
    
    
      @Override public @Nullable MediaType contentType() {
    
    
        return contentType;
      }

      @Override public long contentLength() {
    
    
        return file.length();
      }

      @Override public void writeTo(BufferedSink sink) throws IOException {
    
    
        Source source = null;
        try {
    
    
          source = Okio.source(file);
          sink.writeAll(source);
        } finally {
    
    
          Util.closeQuietly(source);
        }
      }
    };
  }
}

核心方法有三个:

  • contentType() //数据类型
  • contentLength() //数据长度
  • writeTo(BufferedSink sink) //写操作

三.Call分析-同步异步请求流程

Call初始化

我们首先看一下在哪用到了Call:

 Call call = okHttpClient.newCall(request);

无论是get还是post请求 都要生成call对象,在上面我们发现call实例需要一个okHttpClientrequest实例 ,我们先点进Call类去看看:

Call.class

public interface Call extends Cloneable {
    
    
   //返回当前请求
   Request request();
   //同步请求方法,此方法会阻塞当前线程直到请求结果放回
   Response execute() throws IOException;
   //异步请求方法,此方法会将请求添加到队列中,然后等待请求返回
   void enqueue(Callback responseCallback);
   //取消请求
   void cancel();
   //判断请求是否在执行
   boolean isExecuted();
   //判断请求是否取消
   boolean isCanceled();
   //返回请求的超时时间
    Timeout timeout();
    //克隆一个新的请求
    Call clone();
   //工厂接口. Factory中有一个newCall(Request)方法,这说明Call是通过工厂模式创建,而OkHttpClient实现了Call.Factory接口,重写了newCall(Request)方法,返回了Call的具体实现类RealCall
  interface Factory {
    
    
     Call newCall(Request request);
  }
}

我们发现Call是个接口, 并定义了一些方法(方法含义在注释上)。
.
我们继续看newCal()方法

OkHttpClient.class

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

继续点击newRealCall()去:

RealCall.class (RealCall implements Call)

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

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

从代码中我们发现在newRealCall()中初始化了RealCallRealCall中初始化了retryAndFollowUpInterceptor

  • client:OkHttpClient 实例
  • originalRequest :最初的Request
  • forWebSocket :是否支持websocket通信
  • retryAndFollowUpInterceptor 从字面意思来说, 是重试和重定向拦截器 ,至于它有什么作用我们继续往下看

RealCall.class

@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);
    }
  }

从上面代码得知步骤:

(1).通过 synchronized 保证线程同步,判断是否已经执行过 ,如果是直接抛异常

(2). captureCallStackTrace(); 字面意思:捕获调用堆栈跟踪,我们通过源码发现里面涉及到了
retryAndFollowUpInterceptor

(3). eventListener 回调CallStart()

(4). client.dispatcher().executed(this); 看到了dispatcher是不是很熟悉?之前在分析okhttpClient初始化的时候遇到了,我们点击executed()方法进去:

Dispatcher(中文:调度).class

synchronized void executed(RealCall call) {
    
    
    runningSyncCalls.add(call);
}

Dispatcher.class

private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

发现把我们传进来的realcall放到了runningSyncCalls队列中,从字面意思来说就是正在运行的同步的调用队列中,为什么说是队列呢?

Deque即双端队列。是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,相比lis增加[ ] 运算符重载。

(5).我们回到execute()继续往下分析,剩下的代码我们提取出三行代码:

Response result =getResponseWithInterceptorChain(); 生成一个Response 实例

eventListener.callFailed(this, e); :eventListener的callFailed回调

client.dispatcher().finished(this); :dispatcher实例的finished方法

不难看出,getResponseWithInterceptorChain()一定是此方法中的核心,字面意思是获取拦截器链的响应,这就明白了,就是通过拦截器链处理后返回Response

getResponseWithInterceptorChain() 分析

RealCall.class

Response getResponseWithInterceptorChain() throws IOException {
    
    
    //拦截器的添加
    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());     //网络拦截器
    }
    //添加的最后一个拦截器是CallServerInterceptor
    interceptors.add(new CallServerInterceptor(forWebSocket));   //调用服务器拦截器
    
    //创建一个RealInterceptorChain,传入了interceptors和Request
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
   
    return chain.proceed(originalRequest);
  }
}

getResponseWithInterceptorChain()方法最终返回一个Response,也就是网络请求的响应,该方法中首先把用户自定义的拦截器和okhttp默认的拦截器封装到一个List中,然后创建RealInterceptorChain并执行proceed(Request)方法处理请求

从上面代码不难看出, 对最初的request做了层层拦截,每个拦截器的原理我们放在以后的章节去讲, 这里就不展开了!

这里需要强调的一下 interceptors.addAll(client.interceptors()); ,client.interceptors() 是我们自定义的拦截器 它是在哪定义的?如何添加?我们去OkHttpClient类中发现:

OkHttpClient.class

 /**
     * Returns a modifiable list of interceptors that observe the full span of each call: from
     * before the connection is established (if any) until after the response source is selected (either the origin server, cache, or both).
     * 
     * 返回一个可修改的拦截器列表,这些监听器观察每个调用的整个范围:从建立连接之前(如果有)直到选择响应源之后*(源服务器,高速缓存或两者都有)
     */
    public List<Interceptor> interceptors() {
    
    
      return interceptors;
    }

    public Builder addInterceptor(Interceptor interceptor) {
    
    
      if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
      interceptors.add(interceptor);
      return this;
    }

可以通过初始化okHttpClient实例 .addInterceptor的形式 添加。
另外这里涉及到了责任链设计模式,下节具体讲!

异步请求分析

 Call call = okHttpClient.newCall(request);
 call.enqueue(new Callback() {
    
    
      @Override
      public void onFailure(Call call, IOException e) {
    
    
           Log.e(TAG, "onFailure: ");
      }

       @Override
      public void onResponse(Call call, Response response) throws IOException {
    
    
          Log.e(TAG, "onResponse: " + response.body().string());
      }
});

点击enqueue()查看:

RealCall.class

@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));
  }

(1).通过 synchronized 保证线程同步,判断是否已经执行过 ,如果是直接抛异常

(2). captureCallStackTrace(); 字面意思:捕获调用堆栈跟踪,我们通过源码发现里面涉及到了retryAndFollowUpInterceptor

(3). eventListener 回调CallStart()

(4). client.dispatcher().enqueue(new AsyncCall(responseCallback)); 调用了Dispatcher.enqueue()并传入了一个new AsyncCall(responseCallback)实例,点击AsyncCall查看:

RealCall.class

AsyncCallRealCall的内部类!

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

AsyncCall继承了NamedRunnable ,我们看下NamedRunnable是什么:

NamedRunnable.class

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()中 添加了抽象的execute();方法,看到这里 我们应该有一个反应,那就是AsyncCall中具体的execute()应该在子线程执行.

我们继续分析,client.dispatcher().enqueue(new AsyncCall(responseCallback)); 点击进入enqueue()

Dispatcher.class

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);
    }
  }
  • runningAsyncCalls 正在运行的异步请求的队列
  • maxRequests 最大的请求数 64
  • maxRequestsPerHost host最大请求数 5 (可以通过GetSet方式自定义设置)

如果正在运行的异步请求的队列大小低于64并且 正在请求的host数量低于5,就会执行(满足条件)

runningAsyncCalls.add(call);
executorService().execute(call);

这里把 AsyncCall实例添加到 runningAsyncCalls中。
ExecutorService 表示线程池 继续看 executorService()

Dispatcher.class

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

其实就是生成了executorService 实例,这就明白了,AsyncCall实例放入线程池中执行了!

如果不满足上面的请求数等条件:

readyAsyncCalls.add(call);

就会被添加到一个等待就绪的异步请求队列中,目的是什么呢???当然是等待时机再次添加到runningAsyncCalls中并放入线程池中执行,这块逻辑在 AsyncCall类中的 execute() 至于原因我们继续往下看!

刚才我们说了,如果条件满足, AsyncCall实例就会在线程池中执行(.start),那我们直接去看run()中的 execute()

RealCall.class

@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;然后通过一系列的判断,responseCallback进行onResponseonFailure回调,最后调用的Dispatcher.finifshed()

这里需要注意的是 这里的Dispatcher.finifshed(this)与同步中的Dispatcher.finifshed(this)不一样 参数不同。

Dispatcher.class

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

我们继续看具体的finifshed()方法:

Dispatcher.class

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

在线程同步的情况下 执行了promoteCalls();

Dispatcher.class

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

经过一系列的判断, 对等待就绪的异步队列进行遍历,生成对应的AsyncCall实例,并添加到runningAsyncCalls中,最后放入到线程池中执行!这里就是我们上面说到的等待就绪的异步队列如何与runningAsyncCalls对接的逻辑。

总结

同步请求流程:

  • 生成call实例realcall
  • Dispatcher.executed()中的runningSyncCalls 添加realcall到此队列中
  • 通过 getResponseWithInterceptorChain()request层层拦截,生成Response
  • 通过Dispatcher.finished(),把call实例从队列中移除,返回最终的response

异步请求流程:

  • 生成一个AsyncCall(responseCallback)实例(实现了Runnable)

  • AsyncCall实例放入了Dispatcher.enqueue()中,并判断maxRequests
    (最大请求数)maxRequestsPerHost(最大host请求数)是否满足条件,如果满足就把AsyncCall添加到runningAsyncCalls中,并放入线程池中执行;如果条件不满足,就添加到等待就绪的异步队列,当那些满足的条件的执行时,在Dispatcher.finifshed(this)中的promoteCalls();方法中
    对等待就绪的异步队列进行遍历,生成对应的AsyncCall实例,并添加到runningAsyncCalls中,最后放入到线程池中执行,一直到所有请求都结束。

至此OKhttp整体流程就分析完了。

猜你喜欢

转载自blog.csdn.net/gaolh89/article/details/104256816