三方库源码学习-1 :OkHttp

整体框架 :什么,还有这么简单的OkHttp源码分析?
Dispatcher过程 :三方库源码笔记-OkHttp 源码详解
OPPO互联网技术 :​OkHttp源码深度解析

一.OkHttp的源码框架

在这里插入图片描述

1.从一个例子开始

 val okHttClient = OkHttpClient.Builder()
        .connectTimeout(Duration.ofSeconds(10))
        .readTimeout(Duration.ofSeconds(10))
        .writeTimeout(Duration.ofSeconds(10))
        .retryOnConnectionFailure(true)
        .build()
    val request = Request.Builder().url(URL).build()
    val call = okHttClient.newCall(request)
    val response = call.execute()

OkHttp在请求网络的时候,首先是要创建okHttpClient对象,OkHttpClient 包含了对网络请求的全局配置信息,包括链接超时时间读写超时时间链接失败重试等各种配置。然后由okHttpClient执行一个 newCall 方法,将用户编写的request传入,然后就可以执行excuted或者enqueue方法进行网络请求。

2.Call

当调用 okHttClient.newCall(request)时就会得到一个 Call 对象

  override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

它返回的是一个Call类型的接口,实际的实现是 RealCall ,也就是说我们发起的同步异步请求实际上都是靠方法来实现的。它的主要逻辑为:

  1. 判读是否重复请求
  2. 事件记录
  3. 将自身加入到 dispatcher 中,并在请求结束时从 dispatcher 中移除自身
  4. 通过 getResponseWithInterceptorChain 方法得到 Response 对象
override fun execute(): Response {
   
   
	//1.检查是否是同一个请求的再次执行
    check(executed.compareAndSet(false, true)) {
   
    "Already Executed" }
    timeout.enter()
    //2.事件记录,这是OkHttp内部的事件监听
    callStart()
    try {
   
   
    //3.调用dispatcher
      client.dispatcher.executed(this)
      //4.通过 getResponseWithInterceptorChain 方法得到 Response 对象
      return getResponseWithInterceptorChain()
    } finally {
   
   
      client.dispatcher.finished(this)
    }
  }

  override fun enqueue(responseCallback: Callback) {
   
   
  //1.
    check(executed.compareAndSet(false, true)) {
   
    "Already Executed" }
    //2.
    callStart()
    //3.
    client.dispatcher.enqueue(AsyncCall(responseCallback))
  }

注意,这里的异步请求发给dispatcher的是一个AsyncCall对象,他是RealCall的一个内部类,继承了Runable接口。

3.dispatcher

Dispatcher 是一个调度器,用于对全局的网络请求进行缓存调度,RealCall 的同步或者异步请求方法最后又都要进入到 dispatcher调度器中进行调度。其包含以下几个成员变量

class Dispatcher constructor() {
   
   
	//最大请求数
  var maxRequests = 64
    //指向同一Host的最大请求数
   var maxRequestsPerHost = 5
	
	//线程池	
  private var executorServiceOrNull: ExecutorService? = null
  val executorService: ExecutorService
    get() {
   
   
      if (executorServiceOrNull == null) {
   
   
        executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
            SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
      }
      return executorServiceOrNull!!
    }
    
  // 三个双向队列
 
  private val readyAsyncCalls = ArrayDeque<AsyncCall>()
  private val runningAsyncCalls = ArrayDeque<AsyncCall>()
  private val runningSyncCalls = ArrayDeque<RealCall>()

3.1 同步请求:

如果是同步请求,在请求开始前,调度器会把它添加到 同步队列 中,然后调用 getResponseWithInterceptorChain()方法进行真正的网络请求。最后在从同步队列中移除。

// Dispatcher/executed
  @Synchronized internal fun executed(call: RealCall) {
   
   
    runningSyncCalls.add(call)
  }
 

3.2 异步请求:

如果是异步请求,调度器会先把它放在 异步就绪队列 中,该请求是否可以发起受masRequests(请求总数)和maxRequestsPerHost(指向同个主机的请求总数)影响。如果符合条件,那么就会从 异步就绪队列 取出请求加入到 异步运行队列。最后遍历队列,调用每一个对象的executeOn方法。

internal fun enqueue(call: AsyncCall) {
   
   
    synchronized(this) {
   
   
    //加入异步就绪队列 
      readyAsyncCalls.add(call)
    promoteAndExecute()
  }

//  promoteAndExecute()
private fun promoteAndExecute(): Boolean {
   
   
    synchronized(this) {
   
   
      val i = readyAsyncCalls.iterator()
      //遍历异步就绪队列 
      while (i.hasNext()) {
   
   
        val asyncCall = i.next()
        //如果异步运行队列中的请求数大于最大请求个数,直接返回
        if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
        //如果指向同一个主机的请求数大于5,先跳过改请求,继续判断下一个。
        if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
		//如果上面的判断都没问题了,把它加入到异步运行队列中
        i.remove()
        asyncCall.callsPerHost.incrementAndGet()
        //这里的这个可执行队列其实就是异步运行队列的一个拷贝
        executableCalls.add(asyncCall)
        runningAsyncCalls.add(asyncCall)
      }
      isRunning = runningCallsCount() > 0
    }
	//遍历可执行队列,拿到每一个AsyncCall对象,调用它的executeOn方法。
    for (i in 0 until executableCalls.size) {
   
   
      val asyncCall = executableCalls[i]
      asyncCall.executeOn(executorService)
    }
    return isRunning
  }

然后会在executeOn中用传入的线程池执行异步请求。

//AsyncCall/executeOn
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值