65、Okhttp请求流程源码分析

一、Okhttp同步和异步执行流程

OKHttp如何进行同步请求和异步请求?这一切都要从两个官方实例说起:

初始化OkhttpClent

OkHttpClient client = new OkHttpClient.Builder()
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .connectTimeout(10, TimeUnit.SECONDS)
                .build();

异步请求:

final Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        e.printStackTrace();
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d("OkHttpActivity",response.body().string());

    }
});

同步请求:

final Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
Call call = client.newCall(request);
try {
    Response response = call.execute();
} catch (IOException e) {
    e.printStackTrace();
}

小节:
这两种方式都是通过接口Call的具体实现类RealCall来实现的,同一个RealCall只能被执行一次接口请求。

其中同步请求是在当前调用的线程执行,多个同步请求则通过Dispatcher 维护的一个Deque队列,来
保证RealCall的每一次执行顺序。

而异步请求则是在Okhttp对应的线程池中执行,多个异步请求则通过Dispatcher维护的两个Deque队列,来
处理AsyncCall

/** 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<>();
二、从源码的角度分析异步请求:
// 异步请求 mCall 其实是接口Call的实现类 RealCall
mCall.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        e.printStackTrace();
    }
    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d("OkHttpActivity", response.body().string());
    }
});

RealCall的enqueu()方法

@Override public void enqueue(Callback responseCallback) {
  synchronized (this) {
      // executed 全局变量 只被赋值一次,也就是说一个RealCall对象只能被执行一次!!
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  // 捕获调用堆栈跟踪
  captureCallStackTrace();
  // OKHttp 的事件流程监听
  eventListener.callStart(this);
  // 这句是核心逻辑,其实通过OkhttpClient获得 Dispatcher,并调用enqueue方法
  // 将RunAble 的"实现类" AsyncCall 添加 相应的队列中。
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

Dispatcher 的enqueue()

synchronized void enqueue(AsyncCall call) {
    // 这两个判断添加很重要  面试被问过
    // 1、正在运行的异步请求数量 不能超过64 2、当前连接的Host不能超过5个
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    // 将 Runable 添加到正在运行队列中
    runningAsyncCalls.add(call);
    // 开启线程池 执行Runable
    executorService().execute(call);
  } else {
    // 将Runable 添加到 等待线程  
    readyAsyncCalls.add(call);
  }
}

这里:通过maxRequests的限制,避免了请求过多时,手机开启过多的线程;通过maxRequestsPerHost的限制,减少在一个时间点对同一服务器的访问次数,减少服务器的压力。

由于AsyncCall 是接口Runable的实现类,肯定会实现RunAble的Run()方法。

//  AsyncCall 继承
final class AsyncCall extends NamedRunnable
// 而 NamedRunnable 实现 Runnable
public abstract class NamedRunnable implements Runnable

NamedRunnable 主要实现了RunAble的Run方法。

@Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      // RunAble在线程池中执行时调用 
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }
  // 由子类AsyncCall 实现
  protected abstract void execute();
}

AsyncCall 的execute()

@Override protected void execute() {
  boolean signalledCallback = false;
  try {
      // 这句代码先不要管,
      // 只需知道:通过getResponseWithInterceptorChain()方法,能获得请求响应Response
    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 {
       // AsyncCall 执行完毕,调用finished()
    client.dispatcher().finished(this);
  }
}

Dispatcher 的 finished 主要是 1、移除执行完毕的AsyncCall 2、获得下一个 线程池执行

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) {
    // runningAsyncCalls 从运行中的CAll中移除
    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();
  }
}

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

小节:
①、OkHttp异步请求,首先创建接口RunAble的实现类AsyncCall,并将其添加到正在运行的队列或者等待队列中,
②、之后线程池执行AsyncCall(),
③、在AsyncCall() 的 execute()方法中 Response response = getResponseWithInterceptorChain(); 获得网络请求响应,并且通过Callback回调给用户
④、 最后通过 client.dispatcher().finished(this); 从队列中清除执行完毕的AsyncCall ,并且继续下次请求。

至此 OkHttp的异步请求流程梳理完成,下面的这张流程图更加清晰明确OkHttp的异步请求流程
在这里插入图片描述

三、从源码的角度分析同步请求:

相较Okhttp的异步请求,同步请求的流程比较简单点。

// 执行同步请求
Response response =  mCall.execute();

依旧是接口Call的实现类RealCall

@Override public Response execute() throws IOException {
  synchronized (this) {
      // 每个RealCall 这能只执行一次
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  eventListener.callStart(this);
  try {
      // 调用Dispatcher的executed 其实就是将RealCall
      // 添加到同步队列Deque<RealCall> runningSyncCalls = new ArrayDeque<>();之中
    client.dispatcher().executed(this);
    // 暂时不做分析,只需明白调用  getResponseWithInterceptorChain() 获得网络请求响应Response
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
  } catch (IOException e) {
    eventListener.callFailed(this, e);
    throw e;
  } finally {
      // 同步请求 执行完成
      // 将RealCall从 runningSyncCalls 队列中移除
    client.dispatcher().finished(this);
  }
}

向Dispatcher的 Deque runningSyncCalls = new ArrayDeque<>() 添加RealCall

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

向Dispatcher的 Deque runningSyncCalls = new ArrayDeque<>() 移除 执行完毕的 RealCall

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

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

小节:
Okhttp同步请求,所谓的同步请求就是在当前线程进行网络请求,直到网络请求成功或者失败后才能继续执行后续的代码。

至此 OkHttp的同步请求流程梳理完成,下面的这张流程图更加清晰明确OkHttp的同步请求流程
在这里插入图片描述

参考文章链接:

OkHttp的一些实现细节

OkHttp Request 请求执行流程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值