OKHTTP深入浅出(三)----源码流程

OKHttp 基本使用,在上一篇我们已经介绍过OKHTTP深入浅出(二)----基本用法_王胖子总叫我减肥的博客-CSDN博客

之前我们介绍过OKHttp 的OKHttpClient对象和Request对象都是通过建造者模式构建的,首先要理解什么是建造者模式。仿照OKHttpClient的源码,写一个简单的建造模式

public class House {
    private double height;
    private double width;
    private String color;

    public House(Builder builder) {
        this.color = builder.color;
        this.height = builder.height;
        this.width = builder.width;
    }

    public static final class Builder {
        double height;
        double width;
        String color;

        public Builder() {
            this.height = 100;
            this.width = 100;
            this.color = "red";
        }
        
        public Builder setHeight(double height) {
            this.height = height;
            return this;
        }

        public Builder setWidth(double width) {
            this.width = width;
            return this;
        }

        public Builder setColor(String color) {
            this.color = color;
            return this;
        }

        public House build() {
            return new House(this);
        }
    }
}

建造者模式,创建一个house类,属性有height、width、color,在house里面有一个final修饰的静态内部类Builder,在该类中,初始化了3个属性的默认值。同时也可以自己定义属性的值,定义属性值之后,注意返回的是Builder对象;最后在该类中,定义了一个build()方法,其中的this代表用builder,来创建真正的House对象。这就是构建模式。理解了构建模式,能够帮助我们理解OKHttp的源码。

    我们使用GET请求访问网路如下:

//1.构建okHttpClient对象
            OkHttpClient okHttpClient = new OkHttpClient();
            //2.构建request请求对象
            Request request = new Request.Builder().url("www.baidu.com").get().build();
            //3.生成call对象
            Call call = okHttpClient.newCall(request);
            //4.异步请求
            call.enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                }
 
                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    Log.e(TAG,"okhttp get enqueue:" + response.body().string());
                    ResponseBody body = response.body();
                    String string = body.string();
                    byte[] bytes = body.bytes();
                    InputStream inputStream = body.byteStream();
                }

1、OKHttpClinet对象的创建

public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
  final Dispatcher dispatcher;
  final @Nullable Proxy proxy;
  final List<Protocol> protocols;
  final List<ConnectionSpec> connectionSpecs;
  final List<Interceptor> interceptors;
  ....

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

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

 public static final class Builder {
    Dispatcher dispatcher;
    @Nullable Proxy proxy;
    List<Protocol> protocols;
    List<ConnectionSpec> connectionSpecs;
    final List<Interceptor> interceptors = new ArrayList<>();
    ......

    public Builder() { // 默认的配置属性
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();
      if (proxySelector == null) {
        proxySelector = new NullProxySelector();
      }
     .....
    }
    //可自定义的属性
    public Builder connectTimeout(long timeout, TimeUnit unit) {
      connectTimeout = checkDuration("timeout", timeout, unit);
      return this;
    }
   .....
}

  细看一下,发现OKHttpClient 的构建方式和我们上面说的House简直一样,因此不难理解。

2、Request对象的创建,使用的也是构建者模式

public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final @Nullable RequestBody body;
  final Map<Class<?>, Object> tags;

  private volatile @Nullable CacheControl cacheControl; // Lazily initialized.

  Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tags = Util.immutableMap(builder.tags);
  }

  public HttpUrl url() {
    return url;
  }

  public String method() {
    return method;
  }
...
 public static class Builder {
    @Nullable HttpUrl url;
    String method;
    Headers.Builder headers;
    @Nullable RequestBody body;

    /** A mutable map of tags, or an immutable empty map if we don't have any. */
    Map<Class<?>, Object> tags = Collections.emptyMap();

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

    Builder(Request request) {
      this.url = request.url;
      this.method = request.method;
      this.body = request.body;
      this.tags = request.tags.isEmpty()
          ? Collections.emptyMap()
          : new LinkedHashMap<>(request.tags);
      this.headers = request.headers.newBuilder();
    }

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

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

      return url(HttpUrl.get(url));
    }
......

3、 接着查看OKHTTP 的newCall()方法

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

可以看到,其实OKHttpClient的newCall()方法实际上调用的是RealCall的newRealCall()方法。明白了,Call是一个接口,而RealCall实现了这个接口,所以返回new RealCall()call对象当然是没问题的。

 static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);//1
    call.transmitter = new Transmitter(client, call);//2
    return call;
  }

注释1处,来看一下调用的RealCall的构造方法,

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

通过OkHttpClient、Request、forWebSocket参数,创建了一个RealCall实例。

在回头看一下,RealCall的newRealCall()方法中的注释2处,new transmitter(),transmitter翻译为发射器,是应用层和网络层之间的桥梁,在真正进行连接、发出请求、接收响应的时候起到重要的作用。

public Transmitter(OkHttpClient client, Call call) {
    this.client = client;
    this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
    this.call = call;
    this.eventListener = client.eventListenerFactory().create(call);
    this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
  }

可以看到call.transmitter持有了OkHttpClient、连接池、call对象、监听事件eventListener、timeout。

在看一下RealCall的实现类Call。

//  已准备要执行的请求。由于表示单个请求/响应对(流),因此无法执行两次
public interface Call extends Cloneable {
  ...
  //同步请求,会阻塞
  Response execute() throws IOException;

  //异步请求
  void enqueue(Callback responseCallback);

  //取消请求,已经完成的不能取消。
  void cancel();

  boolean isExecuted();
  boolean isCanceled();
  Timeout timeout();
...
  interface Factory {
    Call newCall(Request request);
  }
}

总结一下:OKHTTP 的newCall()方法,其实调用的是RealCall的newRealCall()方法,在RealCall的newRealCall()方法中主要做了两件事,第一件通过OKhttpClient、Request、forWebSocket参数构建了RealCall对象;第二件通过new  Transmitter(client, call)为构建的RealCall对象的transmitter对象赋值。

4、请求的流程

call的请求分为同步请求和异步请求

4.1同步请求

    call.execute()方法,由于call的真正实现是RealCall。因此会调用RealCall的execute()方法。

@Override public Response execute() throws IOException {
    synchronized (this) { //1
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.timeoutEnter();//2
    transmitter.callStart();//3
    try {
      client.dispatcher().executed(this);//4
      return getResponseWithInterceptorChain();//5
    } finally {
      client.dispatcher().finished(this);//6
    }
  }

注释1处,表明了如果请求call只会执行一次的原因。注释2处,发射器开始超时计时;注释3,回调请求监听器的请求开始;注释4,调用了dispatch(调度器)的executed()方法,将请求放入一个双端队列runningSyncCalls中,表示正在执行的同步请求。

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

看看这份runningSyncCalls的声明:

 /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

这个runningSyncCalls是一个队列,从其源代码的注释我们可以得知这个runningSyncCalls的作用是存储当前OkHttpClient正在执行的同步请求

注释5,真正请求返回结果的地方,getResponseWithInterceptorChain()  ,方法的返回值要求是Response对象,因此getResponseWithInterceptorChain()  返回就是Response对象、

注释6,client.dispatcher().finished(this); 请求结束无论如何都会走的地方,此处的this传入的是call请求,会去调用dispatch的finished()方法。

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

       client.dispatcher().finished(this)调用了dispatcher().finished(this)方法并将自身(call)传递了进去,在finished(RealCall call)方法中又调用了finished(Deque<T> calls, T call)方法,传入了runningSyncCalls和我们当前的call对象,还记得这个runningSyncCalls在哪里出现过吗?对的,它在dispater.excuted()方法中出现过,当时的操作是将当前call对象加入到这个runningSyncCalls队列中,那么现在请求结束了,就将当前的call对象移除。

这里注重分析一下getResponseWithInterceptorChain()方法。

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    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, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
      Response response = chain.proceed(originalRequest); //1 
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }

           首先,new了一个interceptors 应用拦截器集合,将应用拦截器(用户配置)client.interceptors()、重试跟进拦截器RetryAndFollowUpInterceptor、桥拦截器BridgeInterceptor、缓存拦截器CacheInterceptor、连接拦截器ConnectInterceptor、网络拦截器(外部配置)client.networkInterceptors()、请求服务拦截器CallServerInterceptor,添加到集合中。

         然后执行

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

   看一下RealInterceptorChain的构造方法

  public RealInterceptorChain(List<Interceptor> interceptors, Transmitter transmitter,
      @Nullable Exchange exchange, int index, Request request, Call call,
      int connectTimeout, int readTimeout, int writeTimeout) {
    this.interceptors = interceptors;
    this.transmitter = transmitter;
    this.exchange = exchange;
    this.index = index;
    this.request = request;
    this.call = call;
    this.connectTimeout = connectTimeout;
    this.readTimeout = readTimeout;
    this.writeTimeout = writeTimeout;
  }

主要是初始化了一个RealInterceptorChain类的对象,注意一下传入的第1个参数(interceptors)和第4个参数(index),分别传入的是我们刚才构成的拦截器集合以及0,一会我们会用到。

       在getResponseWithInterceptorChain()方法的注释1处,Response response = chain.proceed(originalRequest);可以看到,真正返回的response就是从这里的 chain.proceed(originalRequest)方法返回的,当前这个chainRealInterceptorChain类的对象,所以我们来看看RealInterceptorChain.proceed()方法中做了什么

  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, transmitter, exchange);
  }

在跟进看一下,

 public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
      throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.exchange != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    //1
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }

  首先检查了一下index是否超出了interceptorssize,还记得indexinterceptors是什么吗?对的,就是我们在getResponseWithInterceptorChain()源码传入的0和我们初始化的拦截器集合,

  注释1处又初始化了一个RealInterceptorchain()对象,这个那这里初始化的这个RealInterceptorchain对象和之前RealInterceptorChain有什么区别呢?

    可以发现,只有一个参数不一样,就是index参数,现在的RealInterceptorchain传入的index参数是之前的RealInterceptorchain的index +1,然后下一行通过index拿到了interceptors中的元素interceptor(第一个拦截器),这也是proceed()方法的开头为什么先检测index和interceptors.size()大小关系的原因,就是为了防止这发生越界异常。拿到interceptor对象之后,下一行执行了interceptor.intercept(next)并返回了response,而最后也是将这个response最终作为当前proceed()方法的返回值,这时候我们就有必要深入一下interceptor.intercept(next)的源码了,我们尝试跟踪源码,会发现这个Interceptor其实是一个接口:

 看一下这个接口的实现类。

 我们看到了5个拦截器类,由于当前interceptor是通过interceptors.get(index)拿到的,而index当前传入的值为0,所以第一次执行的应该是第一个加入拦截器集合的那个拦截器类的intercept()方法,这里我们先不考虑用户自添加的拦截器,那么第一个拦截器就应该是RetryAndFollowUpInterceptor拦截器,我们来看看它的intercept()方法:
 

@Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    RealInterceptorChain realChain = (RealInterceptorChain) chain;//1
    Transmitter transmitter = realChain.transmitter();

.......
      }

      Response response;
      boolean success = false;
      try {
        response = realChain.proceed(request, transmitter, null);//2
        success = true;
      } catch (RouteException e) {
    .....

注释1,将当前传入的chain转换成RealInterceptorChain对象;注释2,执行了realChain.process( request, transmitter, null)并且返回了Response。其中这个realChain就是我们当前调用的intercept()方法传入的chain参数。

 RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

即由interceptorsindex 1构建的新的RealInterceptorChain,所以整个逻辑就是:

因此整个逻辑就是:

可以发现,整个拦截器集合构成了一个链式结构,当前拦截器执行完对应的拦截方法后激活下一个拦截器开始工作,直到最后一个拦截器,这也告诉我们如果要添加自定义的拦截器,则必须在重写intercept(Chain chain)方法时返回chain.proceed(),否则责任链就会断链,自然不会成功地发起网络请求。

注意由于CallServerInterceptor这个拦截器是最后一个拦截器,所以它的intercept方法中没有像之前的拦截器那样执行next.proceed(),而是直接使用传入的Chain chain参数直接发起了网络请求并返回Response。
 

总结一下同步请求的流程

  1.  Realcall.execute()发起同步网络请求。
  2. 利用execute标志位判断是否当前的call对象已经执行过了,若执行就抛出异常。
  3. 调用client.dispatcher.excuted(),将当前的call对象加入到runningSynccalls队列。
  4. 调用getResponseWithInterceptorChain()方法,内部试用责任链模式依次执行拦截器中的拦截器,最终发起网络请求,返回Response、
  5. 调用Client.dispatch.finished(),将当前call对象从runningSynccalls队列移除。
  6. 返回Response对象

4.2 异步请求

异步请求使用call.enqueue()方法

call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {              
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

同理调用的也是RealCall的enqueue()方法。

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

注释1,异步请求enqueue也只能请求一次。注释2,回调请求监听器的请求开始。注释3,调用Dispatcher的enqueue方法,参数接受的是AsyncCall,AsyncCall继承NamedRunnable,NamedRunnable实现自Runnable,即AsyncCall就是个Runnable,可以想到它是会在线程或线程池执行run方法的。run方法在AsyncCall没看到啊,实际是在NamedRunnable中:

  final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;
    private volatile AtomicInteger callsPerHost = new AtomicInteger(0);

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }
   .....
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();
}

回头在看一下注释3中的dispatcher的enqueue()方法,

  void enqueue(AsyncCall call) {
    synchronized (this) {
      readyAsyncCalls.add(call);// 1
      // 2 
      if (!call.get().forWebSocket) { 
        AsyncCall existingCall = findExistingCallWithHost(call.host());//3
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);//4
      }
    }
    promoteAndExecute(); //5
  }

注释1处。将请求放入等待队列。注释2,判断请求call是否是有相同的host(通过findExistingCallWithHost()方法)

@Nullable private AsyncCall findExistingCallWithHost(String host) {
    for (AsyncCall existingCall : runningAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    for (AsyncCall existingCall : readyAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    return null;
  }

从运行队列runningAsyncCalls和的等待队列readyAsyncCalls寻找到相同的host请求。

注释4,找到的相同的host请求后,将callsPerHost重用给当前请求。

 void reuseCallsPerHostFrom(AsyncCall other) {
      this.callsPerHost = other.callsPerHost;
    }

就是对call对象的callsPerHost进行了更新,注意这里是直接使用了=对this.callsPerHost进行了赋值,而且在java中参数默认传递的是引用,所以当前callsPerHost和findExistingCallWithHost()中返回的那个AsyncCall对象的callsPerHost是同一个引用,那么再延伸一下,所有host相同的AsyncCall对象中的callsPerHost都是同一个引用,即如果改变其中一个AsyncCall对象的callsPerHost值,其他的所有AsyncCall对象的 callsPerHost的值也会随之改变,下面我们会看到作者巧妙地利用了这一点更新了所有host相同的 AsyncCall对象的callsPerHost值,实在是非常优秀。 这个callPerHost的声明如下,即初始值为0。

private volatile AtomicInteger callsPerHost = new AtomicInteger(0);

注释5,在同步请求中finished()方法中就调用了promoteAndExecute()方法,在这里异步请求中又一次调用了该方法,这个方法到底做了什么事呢?

  private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));

    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      //1
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();

        if (runningAsyncCalls.size() >= maxRequests) break; // 2.
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // 3

        i.remove(); //4
        asyncCall.callsPerHost().incrementAndGet(); //5
        executableCalls.add(asyncCall); //6
        runningAsyncCalls.add(asyncCall); //7
      }
      isRunning = runningCallsCount() > 0;
    }

    //8
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }

这个方法为调度的核心方法:注释1,遍历了readyAsyncCalls这个队列,对于readyAsyncCalls中的每一个被遍历的当前AsyncCall对象,

注释2,会首先判断runningAsyncCalls这个队列的长度是否大于了maxRequests,这个maxRequests默认是64,意思就是说要求当前正在执行的网络请求不能超过64个(为了节约资源考虑),如果大于就直接返回。

注释3,判断asyncCall.callsPerHost().get()是否大于maxRequestsPerHost,maxRequestsPerHost的值默认为5,上面我们说到callsPerHost的初始为0,那么asyncCall.callsPerHost().get()初始应该是小于maxRequestsPerHost的,这里这个判断的意思就是当前正在执行的所有的请求中,与asyncCall对应的主机(host)相同请求的数量不能超过maxRequestsPerHost也就是5个,如果满足条件即同一个host的请求不超过5个。

注释4,首先将当前AsyncCall对象从readyAsyncCalls中移除。

注释5,就是将callsPerHost的值增1,上面提到,所有host相同的AsyncCall对象中的callsPerHost都是同一个引用,所以这里对当前这个callsPerHost的值增1实际上是更新了readyAsyncCalls中的所有AsyncCall对象中的callsPerHost的值,这样callsPerHost这个属性值就能够表示请求host与当前host相同的请求数量。

注释6,将当前AsyncCall加入到executableCalls(可执行请求队列中),执行所有executableCalls中的请求

注释7,将当前AsyncCall加入运行队列runningAsyncCalls,表示请求正在运行。

注释8,主要是对executableCalls进行了遍历,对于executableCalls中的每一个AsyncCall对象,执行asyncCall.executeOn()方法,传入了一个executorService(),首先看executorService()的源码:

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,最大线程数为Integer.MAX_VALUE(不限制),这是将线程池的最大线程数设置为Integer.MAX_VALUE的原因是:在Dispatcher中默认使用了maxRequest控制了同时并发的最大请求数,因此这里就不用加以控制了,然后设置了最大线程的最大存活时间为60S,就是说当前线程任务执行完毕之后,60S之内不会被销毁,如果此时有其他网络请求的任务,就不用新建线程,可以之前复用当前的线程。

在看一下asyncCall.executeOn()方法,

    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try { 
        executorService.execute(this);  //1
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        transmitter.noMoreExchanges(ioException);
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }

  尝试将此asyncCall调用加入 executorService。 如果执行程序已通过报告调用失败而关闭,这将尝试进行清理。

注释1,是该方法的核心步骤,主要调用线程池executorService的execute()方法来执行当前asyncCall,之前说过asyncCall是实现了Runnable接口的。

final class AsyncCall extends 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()方法主要是调用了抽象方法execute()方法,而execute()抽象方法会被asyncCall实现。所以,AsyncCall类的run()方法实际上执行的是其execute()中的内容:

    @Override protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
        Response response = getResponseWithInterceptorChain();//1
        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);
        }
      } catch (Throwable t) {
        cancel();
        if (!signalledCallback) {
          IOException canceledException = new IOException("canceled due to " + t);
          canceledException.addSuppressed(t);
          responseCallback.onFailure(RealCall.this, canceledException);
        }
        throw t;
      } finally {
        client.dispatcher().finished(this);//2
      }
    }

     可以看到,execute()方法中发起了真正的网络请求,核心方法是注释1,getResponseWithInterceptorChain(),这其作用是发起网络请求,返回Response,注意这里使用了try...catch语句块对异常进行了捕捉,如果发生异常,则调用responseCallback.onFailure(RealCall.this, e),而这个responseCallback就是我们发起异步请求时传入的那个CallBack对象,所以就是在这里回调的onFailure()方法。如果请求成功,则调用responseCallback.onResponse(RealCall.this, response)即我们的onResponse()回调方法。

      那么由于当前execute()方法是在Runnable接口的run()方法中被调用的,而asyncCall又被传入了executorService.execute()中,所以当前execute()方法会在线程池中被执行,即onFailure()和onResponse()这两个回调方法会在子线程被调用,这也说明了我们不能再RealCall.enqueue()方法的回调中直接更新UI,因为其回调方法都是在子线程被调用的。
   注释2,client.dispatcher().finished(this),this指的的asyncCall,

void finished(AsyncCall call) {
    call.callsPerHost().decrementAndGet();
    finished(runningAsyncCalls, call);
  }
其中call.callsPerHost().decrementAndGet(),将AsyncCall的callsPerHost的值减去1,因为当前的AsyncCall已经结束了,那么就应该将与当前AsyncCall具有相同的host的请求数量减去1,然后调用了
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();
    }
  }

主要将当前的AsyncCall从runningAsyncCalls中移除。

总结一下异步请求的流程:

  1. 调用call.enqueue(Callback callback),传入call回调。
  2. 将当前的call对象转化为AsyncCall对象,调用Client.dispatch.enqueue(),调用OKHttpClinet的dispatch对象的enqueue()方法。
  3. 将当前的AsyncCall对象加入readyAsyncCalls队列。
  4. 遍历readyAsyncCalls,将符合条件的AsyncCall移除并加入到executableCalls和 runningAsyncCalls集合。
  5. 遍历executable集合,执行每一个AsyncCall对象的execute()方法,传入线程池。
  6. 在线程池中发起当前的AsyncCall的网络请求。
  7. 回调成功或者失败对应的回调方法。
  8. 将当前的AsyncCall对象从runningAsyncCalls中移除。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值