OkHttp3源码解析01-请求

使用OkHttp进行请求,我们首先需要构建一个Request对象,可以看到这里使用建造者模式创建了一个Request对象,之后再传入request,生成Call对象。

 Request request = new Request.Builder()
    .url("http://xxx/yyy")
    .method("GET", null)
    .build();  
OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);

获得Call对象后,可以调用enqueue进行异步请求

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

    }

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

    }
});  

也可以通过调用execute进行同步请求

Response response = call.execute();  

总之,无论是调用enqueue还是execute,都会调用Dispatcher来执行。

下面以enqueue为例,会调用到RealCall.enqueue

public void enqueue(Callback responseCallback) {
    enqueue(responseCallback, false);
}

void enqueue(Callback responseCallback, boolean forWebSocket) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}

这里的client.dispatcher()就是一个Dispatcher对象,Dispatcher是个任务调度类,主要用作控制并发的请求,Dispatcher有几个重要的属性,我们先来看一下

//最大并发请求数
private int maxRequests = 64;
//每个主机的最大请求数
private int maxRequestsPerHost = 5;
//消费者线程池
private ExecutorService executorService;
//将要运行的异步请求队列 
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在运行的异步请求队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在运行的同步请求队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
//主机最大请求数
private int maxRequestsPerHost = 5;  

再来看Dispatcher.enqueue

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

private int runningCallsForHost(AsyncCall call) {
    int result = 0;
    for (AsyncCall c : runningAsyncCalls) {
      if (c.host().equals(call.host())) result++;
    }
    return result;
}

可以看到,如果正在运行的异步请求队列小于最大请求数,并且每个主机的请求数小于主机最大请求数,那么会将这个AsyncCall加入到runningsAsyncCalls队列中,并会调用executorService()

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通过线程池立即执行。

否则,会将AsyncCall加入到readyAsyncCalls队列,等待执行。

再来看下AsyncCall这个类,这个类在上面RealCall.enqueue中,会进行创建

client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));  

可以看到,它在构造方法中传入了responseCallback,这个也就是我们调用Call.enqueue时候传入的回调。

主要来看AsyncCall.execute,线程池在执行时会调用这个方法。

protected void execute() {
  boolean signalledCallback = false;
  try {
    Response response = getResponseWithInterceptorChain(forWebSocket);
    if (canceled) {
      signalledCallback = true;
      responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
    } else {
      signalledCallback = true;
      responseCallback.onResponse(RealCall.this, response);
    }
  } catch (IOException e) {
    //...
    responseCallback.onFailure(RealCall.this, e);
  } finally {
    client.dispatcher().finished(this);
  }
}  

首先,会调用getResponseWithInterceptorChain()来获得Response对象,getResponseWithInterceptorChain()也就是真正执行请求的地方。

之后,会根据结果调用responseCallback.onFailure或者responseCallback.onResponse

但最终,无论是否请求成果,都会调用client.dispatcher().finished()client.dispatcher()我们已经很熟悉了多好就是DIspatcher对象。

  synchronized void finished(AsyncCall call) {
    if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
    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.
    }
  }

可以看到,这里首先把这个AsyncCall从runningAsyncCalls中移除,并在promoteCalls的时候,从readyAsyncCalls中取出下一个AsyncCall,并加入到runningAsyncCalls队列并通过调用线程池执行。

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

总结

OkHttp的请求流程,主要步骤如下
1. 通过建造者模式构建出Request对象
2. 传入Request对象构建出Call对象
3. 通过Call.enqueue或Call.execute来进行异步或同步的请求

Call的内部请求流程,主要步骤如下
1. 传入请求回调responseCallback生成AsyncCall对象
2. 通过Dispatcher.enqueue(),传入AsyncCall
3. 如果符合请求数和主机请求数,则将AsyncCall加入到runningAsyncCalls正在运行的异步请求队列,并通过线程池执行AsyncCall
4. 否则,将AsyncCall加入到readyAsyncCalls将要运行的异步请求队列 ,等待执行
5. 通过AsyncCall.getResponseWithInterceptorChain()执行真正的请求,并进行相应的回调
6. 调用Dispatcher.finished(),将AsyncC从runningAsyncCalls队列中移除,并将下一个AsyncCall从readyAsyncCalls中获取,加入到runningAsyncCalls队列中,并通过线程池执行。

至此,OkHttp的请求流程的源码就已经解析完了。下篇文章我们将分析下OkHttp的拦截器。

源码分析中的OkHttp版本为com.squareup.okhttp3:okhttp:3.2.0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值