OKHTTP 源码分析(1)调用流程梳理

本文深入分析了OkHttp 3.10.0版本中异步请求的实现原理,从OkHttpClient配置、Request构建、Call调度到RealCall与Dispatcher的协作机制,再到AsyncCall的执行过程,详细解读了OkHttp异步请求的完整流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

序 、最近因为一些原因 ,会连续记录学习的一些笔记 。

 

背景

PS:OKHTTP 版本为 3.10.0 

api 'com.squareup.okhttp3:okhttp:3.10.0'

get 请求示例代码

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

        final Request request = new  Request.Builder().url("www.baidu.com").get().build();
        Call call = okHttpClient.newCall(request);

        同步方法
        try {
            Response execute = call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }

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

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String string = response.body().string();
                response.body().byteStream();

            }
        });

核心类 OkHttpClient 、Request 、Call 、RealCall 、Dispatcher 、Deque 、AsyncCall 、Response  。

 

流程梳理

1. OkHttpClient 网络配置层

使用构建者模式创建实例 (在后续文章会详细介绍构建者模式)。

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

下图是此构建者可以 add 的参数配置 。我们平时最常使用的比如添加拦截器操作 ,就是通过此构建者 。

2. Request 当前请求体

使用构建者模式创建实例 (在后续文章会详细介绍构建者模式)。

final Request request = new  Request.Builder().url("www.baidu.com").get().build();

3. Call 可以操作异步也可以操作同步 。

Call call = okHttpClient.newCall(request);

我们先来分析一下 Call 对象  ,直接进入 newcall 方法 。如下 ,最终返回的是 RealCall 对象 ,RealCall 是 Call 接口的实现类 。

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

我们直接分析异步方法调用

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

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String string = response.body().string();
                response.body().byteStream();

            }
        });

4. RealCall 作为 Call 的实现类 ,重写了 Call 的异步方法 enqueue ,我们直接进入 RealCall 类里面查看 enqueue 。

来源 :RealCall 

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

我们先来看此方法前三行的加锁代码 ,意思是不能请求两次异步方法 。可以自己写个 demo ,异步方法在写一遍如下 。运行之后一定会报错 Already Executed 。 

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

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String string = response.body().string();
                response.body().byteStream();

            }
        });



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

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String string = response.body().string();
                response.body().byteStream();

            }
        });

5. RealCall 的 enqueue 方法的最后一行代码   任务调度器 Dispatcher 。

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

RealCall 的 enqueue 方法最后调用的是任务调度器 Diaspatcher 的 enqueue 方法 ,会传去一个 AsyncCall 参数 。

任务调度器 Dispatcher 类

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

首先看方法体里面的内容 。有几个参数 。

双端队列 :Deque 

运行队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
等待队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

最大请求数量
private int maxRequests = 64;

最大请求 HOST
private int maxRequestsPerHost = 5;

PS:首先我们看方法里面的判断条件 :

runningAsyncCalls.size() < maxRequests  运行队列的数量小于 64 个 ,意思是同时运行的异步任务不能超过 64个 。

 runningCallsForHost(call) < maxRequestsPerHost 不能同时访问 5 个 Host端口 。

如果满足以上条件 ,则会被添加到 runningAsyncCalls 队列 。然后在执行 ,否则的话 ,就会被加入等待队列 readyAsyncCalls.add(call) 。

6. 任务调度器传入一个 AsyncCall ,我们来看一下这个类 。

点进去发现 AsyncCall 是 RealCall 的一个内部类 。实现了 NameRunnable 接口 ,接口有实现了 Runnable 。作为一个线程 ,重写 Run 方法 ,并且调用抽象方法 execute 。所以我们来看 AsyncCall 重写的方法 execute 方法 。

RealCall 的内部类 AsyncCall 重写的抽象方法 


  @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 。这个之后在详细写写 ,在此跳过 。

PS:我们来看一下这个 try catch 。需要注意一个变量  signalledCallback ,在 try 里面无论是走成功还是失败的回调 ,都会把这个变量设置为 true 。然后在 catch 里面 如何为 true 的话 ,就直接打印说是你用户的错 ,跟OKHTTP 无关 ,符合程序员的形象 ,不甩锅也不替别人背锅 。

解释一下 。

如果 是 这行代码 Response response = getResponseWithInterceptorChain(); 发生异常 ,则直接在catch里面走失败回调 。如果已经走过成功失败回调 ,证明 response 是没有问题的 我们可以看下异步回到的方法 。

 //异步方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String string = response.body().string();
                response.body().byteStream();

            }
        });

在 onResponse 回调中国如果因为我们自己的代码逻辑错误抛出异常 ,则回到 execute 方法中就会到 catch 中 ,然后变量signalledCallback 告诉你这是你自己的问题,不是 OKHTTP 的问题 。

 

OKOK END 、

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值