OkHttp3源码分析(上):请求流程

OkHttp是android源码中提供的网络请求框架,是Square公司的经典作品之一
源码 git@github.com:square/okhttp.git

以下源码分析基于3.9.0


1. OkHttp3使用步骤

使用步骤可分为4步:

1.1 创建OkHttpClient

Builder模式创建OkHttpClient,可以添加自定义拦截器,以及配置各种参数(鉴权、超时等)。

1.2 创建Request

Builder模式创建请求对象,配置请求url以及method,自定义请求头Header也是在这里添加。

1.3 创建Call

OkHttpClient#newCall(request)
具体实现为RealCall,将OkHttpClient以及Request包装成RealCall对象。

1.4 将call提交到队列

请求分为两种:异步Async、同步Sync。
1. 异步请求
调用call.enqueue(callback), 内部实现是将call加入runningAsyncCalls并调用线程池执行或者readyAsyncCalls等待执行;
2. 同步请求
调用call.execute(callback),内部实现是将call加入runningSyncCalls,在当前线程执行请求.

这些容器都是双端队列ArrayDeque,具体执行细节后面再详细描述。

示例代码如下:

	// step 1
	OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
	OkHttpClient client = clientBuilder.build();
	// step 2
	Request.Builder requestBuilder = new Request.Builder();
	requestBuilder.url("https://www.baidu.com");
	// step 3
	Call call = client.newCall(requestBuilder.build());
	// step 4
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            System.out.println("IOException: " + e.getMessage());
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            System.out.println(response.toString());
            System.out.println("body: " + response.body().string());
        }
    });

2. 源码时序图分析 (异步请求为例)

时序图描述了用户发起一个 异步请求RealCall ,到RealCall返回callback响应结果的大概逻辑。
RealCall如何拿到response?这里还涉及到Dispatcher以及RealInterceptorChain的逻辑,后续章节再详细描述。

在这里插入图片描述

2.1 创建OkHttpClient与添加拦截器

Interceptor可以帮助我们分析、处理请求过程(修改Request与Response)。

    private OkHttpClient getOkHttpClient() {
        File file = new File(CACHE_PATH);
        if (!file.exists()) {
            file.mkdirs();
        }
        Cache cache = new Cache(file, CACHE_SIZE);

        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .addInterceptor(InterceptorManager.getRequestInterceptor()) // Request拦截器
                .addInterceptor(InterceptorManager.getResponseInterceptor()) //Response拦截器
                .addInterceptor(InterceptorManager.getLogInterceptor()) // Log拦截器
                .addNetworkInterceptor(InterceptorManager.getNewWorkInterceptor())
                .cache(cache)//开启缓存
                .build();

        return client;
    }

2.2 添加请求(以异步请求为例)

2.2.1 RealCall#enqueue

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

RealCall内部逻辑实现,将请求交给Dispatcher来管理与分发。

2.2.2 Dispatcher#enqueue

按照当前请求队列的情况,添加到对应的队列中,对请求数量进行有效的管控。

runningAsyncCalls
进行请求 的队列,当进行请求队列数量<64 && 目标Host同时处理的请求<5,则将call添加到队列,并且调用线程池执行当前请求。
readyAsyncCalls
等待请求 的队列,不满足上述条件,call就加入等待请求队列。

2.2.3 Dispatcher#promoteCalls

当一个请求完成后,检测是否需要将readyAsyncCalls中的请求转移到runningAsyncCalls队列。
RealCall#AsyncCall内部执行完请求,会在finally代码块触发promoteCalls方法。

1.runningAsyncCalls队列容量已达到64,返回
2.没有达到64,则迭代readyAsyncCalls队列,将call转到进行队列并调用线程池执行请求
3.转移一个call,就需要再检查进行队列容量,达到64就退出

  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;
  
  // 如果runningAsyncCalls队列“已满”,则加入等待队列readyAsyncCalls
  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

  // 完成一个请求,则进行判断,是否需要将等待队列中的请求移动到进行队列中,有则进行移动操作,并开始请求
  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.
    }
  }

2.3 线程池的实现

  // 自定义线程池,核心线程为0
  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;
  }

2.4 Call - RealCall - AsyncCall

传入的Call对象实为AsyncCall,AsyncCall是RealCall的内部类,实现类Runnable接口。

AsyncCall 持有RealCall的originalRequest以及responseCallback。

execute()方法中,完成请求,并invoke通知callback回调,最后还要通知上面步骤2.2.3的操作,检测是否可以将等待队列中的call转移到进行队列中。

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 {
      // run()方法中调用execute()
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }
  // 此抽象方法,是每一个Call对象的具体实现,模板方法模式
  protected abstract void execute();
}

AsyncCall#execute(),调用流程在父类中定义,这里是具体实现,模版方法模式。

    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        // 获取请求结果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 {
      	// 完成请求,触发call从等待队列到进行队列的转移
        client.dispatcher().finished(this);
      }
    }

3 类图说明

在这里插入图片描述

  1. OkHttpClient用来创建请求,添加Interceptor;
  2. RealCall是Call的实现类,用来发起请求,AsyncCall定义了异步请求过程;
  3. Dispatcher用来管理请求队列,触发线程池进行请求(异步请求调用线程池,同步请求只是用dispatcher来管理请求队列);
  4. Interceptor的实现类是具体的请求过程,责任链模式;
  5. 请求结果response在AsyncCall中返回给Client。

说明:上述步骤均是指异步请求,关于同步请求有几点不同
第2步,同步请求直接在RealCall#execute()方法中执行;
第3步,同步请求只是用dispatcher来管理请求队列(进行队列:runningAsyncCalls + runningSyncCalls);
第5步,同步请求结果直接在RealCall#execute()方法中返回。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值