【Android】OKhttp主流程分析

前言

本文基于okhttp3:4.9.3进行分析:

implementation("com.squareup.okhttp3:okhttp:4.9.3")

请求流程:

  1. 创建OkHttpClient对象:OkHttp.Build().build()
  2. 创建Reques对象:Request.Builder().build()
  3. 异步请求:client.newCall(request).enqueue()

newCall(request)

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

OkhttpClient.newCall(request)其实就是生成一个RealCall对象,接着去看RealCall.enqueue()方法。

RealCall.enqueue()

override fun enqueue(responseCallback: Callback) {
  check(executed.compareAndSet(false, true)) { "Already Executed" }

  callStart() ①
  client.dispatcher.enqueue(AsyncCall(responseCallback)) ②
}
  
private fun callStart() {
  this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()")
  eventListener.callStart(this)
} 

①处并不是去执行真正的网络请求,我们在callStart()方法中可以看到,只是执行了eventListener.callStart(),这个Listener只是用来记录HTTP调用的数量、大小和持续时间,下面是EventListener的注释信息。

Listener for metrics events. Extend this class to monitor the quantity, size, and duration of your application’s HTTP calls.

②处才是我们需要关注的流程,接着我们进入Dispatcher.enqueue()方法。

Dispatcher.enqueue()

internal fun enqueue(call: AsyncCall) {
  synchronized(this) {
    // 添加到待执行的队列中
    readyAsyncCalls.add(call) ①

    // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
    // the same host.
    if (!call.call.forWebSocket) {
      val existingCall = findExistingCallWithHost(call.host)
      if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
    }
  }
  promoteAndExecute() ②
}

private fun promoteAndExecute(): Boolean {
  this.assertThreadDoesntHoldLock()

  val executableCalls = mutableListOf<AsyncCall>()
  val isRunning: Boolean
  synchronized(this) {
    // 遍历待执行的队列,取出call
    val i = readyAsyncCalls.iterator() ③
    while (i.hasNext()) {
      val asyncCall = i.next()

      if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
      if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.

      i.remove()
      asyncCall.callsPerHost.incrementAndGet()
      executableCalls.add(asyncCall)
      // 放入正在执行的队列中
      runningAsyncCalls.add(asyncCall) ④
    }
    isRunning = runningCallsCount() > 0
    
    for (i in 0 until executableCalls.size) {
      val asyncCall = executableCalls[i]
      // 执行AsyncCall.executeOn()方法
      // executorService为线程池
      asyncCall.executeOn(executorService) ⑤
    }

    return isRunning
  }
  
@get:JvmName("executorService") val executorService: ExecutorService
get() {
  if (executorServiceOrNull == null) {
    executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
        SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
  }
  return executorServiceOrNull!!
} 

这个流程我们逐一分析:

①处首先将请求方法待执行的队列中,也就是readyAsyncCalls

②处调用promoteAndExecute()去做一些执行前的准备工作;

③处遍历待执行的队列readyAsyncCalls

④处将这些待执行的请求,添加到正在执行的队列runningAsyncCalls中;

⑤处调用AsyncCall.executeOn(executorServicer)方法。

这里提一下executorService是一个核心数为0,最大线程数为Int最大值的一个线程池,用来异步执行网络请求。

接下来我们继续进入AsyncCall.executeOn(executorServicer)

AsyncCall.executeOn()

fun executeOn(executorService: ExecutorService) {
  client.dispatcher.assertThreadDoesntHoldLock()

  var success = false
  try {
    executorService.execute(this) ①
    success = true
  } catch (e: RejectedExecutionException) {
    val ioException = InterruptedIOException("executor rejected")
    ioException.initCause(e)
    noMoreExchanges(ioException)
    responseCallback.onFailure(this@RealCall, ioException)
  } finally {
    if (!success) {
      client.dispatcher.finished(this) ② // This call is no longer running!
    }
  }
}

private fun <T> finished(calls: Deque<T>, call: T) {
  val idleCallback: Runnable?
  synchronized(this) {
    if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!") ③
    idleCallback = this.idleCallback
  }

  val isRunning = promoteAndExecute()

  if (!isRunning && idleCallback != null) {
    idleCallback.run()
  }
} 

①处转到线程池的execute(this)方法中,接下来分析;

②处当执行结束进行到finally中的时候去③处将此次请求从runningSyncCalls队列中移除。

上面我们提到,最终请求是转到了ExecutorService.execute(this)中,此时我们可以看下AsyncCall是实现了Runnable接口的,所以最终还是调用的AsyncCall.run()方法,这样我们就可以去run()中寻找接下来的流程了。

AsyncCall.run()

 override fun run() {
    threadName("OkHttp ${redactedUrl()}") {
      var signalledCallback = false
      timeout.enter()
      try {
        // 去执行请求
        val response = getResponseWithInterceptorChain() ①
        signalledCallback = true
        // 回调正常的情况
        responseCallback.onResponse(this@RealCall, response) ②
      } catch (e: IOException) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
        } else {
          // 回调异常
          responseCallback.onFailure(this@RealCall, e) ③
        }
      } catch (t: Throwable) {
        cancel()
        if (!signalledCallback) {
          val canceledException = IOException("canceled due to $t")
          canceledException.addSuppressed(t)
          // 回调异常
          responseCallback.onFailure(this@RealCall, canceledException)
        }
        throw t
      } finally {
        // 将call在runningQueue移除
        client.dispatcher.finished(this)
      }
    }
  }
} 

①这里就是去真正执行网络请求的起始点,可以通过getResponseWithInterceptorChain()拿到接口回调;

②回调网络请求结果。

重点看下getResponseWithInterceptorChain()

getResponseWithInterceptorChain()

internal fun getResponseWithInterceptorChain(): Response {
  // Build a full stack of interceptors.
  val interceptors = mutableListOf<Interceptor>() ①
  // 添加拦截器
  // interceptor可以处理干净的Request
  interceptors += client.interceptors
  // 重试、重定向操作
  interceptors += RetryAndFollowUpInterceptor(client)
  // 帮我们补充数据,比如content_length,根据body计算大小
  interceptors += BridgeInterceptor(client.cookieJar)
  // 用来处理缓存,是否可以使用缓存数据等
  interceptors += CacheInterceptor(client.cache)
  // 去和服务器建立连接,这里包括了三次握手
  interceptors += ConnectInterceptor
  if (!forWebSocket) {
    // networkInterceptors是经过重试重定向、桥接、缓存、连接拦截之后的Request,一般不推荐
    interceptors += client.networkInterceptors
  }
  // 真正去执行内容请求的拦截器
  interceptors += CallServerInterceptor(forWebSocket)

  val chain = RealInterceptorChain(
      call = this,
      interceptors = interceptors,
      index = 0,
      exchange = null,
      request = originalRequest,
      connectTimeoutMillis = client.connectTimeoutMillis,
      readTimeoutMillis = client.readTimeoutMillis,
      writeTimeoutMillis = client.writeTimeoutMillis
  ) ②

  var calledNoMoreExchanges = false
  try {
    // 执行拦截器得到最终的Response
    val response = chain.proceed(originalRequest) ③
    if (isCanceled()) {
      response.closeQuietly()
      throw IOException("Canceled")
    }
    return response
  } catch (e: IOException) {
    calledNoMoreExchanges = true
    throw noMoreExchanges(e) as Throwable
  } finally {
    if (!calledNoMoreExchanges) {
      noMoreExchanges(null)
    }
  }
} 

①处这里添加请求拦截器:

  • client.interceptors是我们通过OkHttpClient.Builder().addInterceptor()添加的自定义拦截器,需要注意的是,这里的Request是最干净的请求,没有被其它拦截器进行修改,一般我们可以添加日志信息打印拦截器、公共头参拦截器等;
  • RetryAndFollowUpInterceptor用来重试、重定向操作的一个拦截器;
  • BridgeInterceptor这个拦截器主要就是帮助我们补充一些请求信息,比如:conten_length,requestBody大小等信息;
  • CacheInterceptor用来处理缓存,是否可以使用缓存数据等;
  • ConnectInterceptor去和服务器建立连接,这里包括了三次握手;
  • client.networkInterceptors是我们通过OkHttpClient.Builder().addNetworkInterceptor()添加的自定义网络拦截器,这里我们可以出来,它的调用前面已经经历了一些重定向、桥接、缓存拦截器,并不是原始的Request
  • CallServerInterceptor真正去执行内容请求的拦截器。

关于拦截器是如何工作的,我会再后续文章详细介绍,这里就不深入探讨了。

②处创建了一个RealInterceptorChain对象,记住一个信息index = 0,它是后续拦截器责任链工作的重点因素之一;

③调用了RealInterceptorChain.proceed()方法,开启责任链。

RealInterceptorChain.proceed

 override fun proceed(request: Request): Response {
    check(index < interceptors.size)

    calls++

    // Call the next interceptor in the chain.
    val next = copy(index = index + 1, request = request) ①
    val interceptor = interceptors[index] ②

    @Suppress("USELESS_ELVIS")
    val response = interceptor.intercept(next) ③ ?: throw NullPointerException(
        "interceptor $interceptor returned null")

    if (exchange != null) {
      check(index + 1 >= interceptors.size || next.calls == 1) {
        "network interceptor $interceptor must call proceed() exactly once"
      }
    }

    check(response.body != null) { "interceptor $interceptor returned a response with no body" }

    return response
  } 

①这里提前copy下一个的Chain对象;

②拿到当前的拦截器;

③这里调用拦截器interceptor.intercept(chain)方法,在这个方法里面,会依次调用chain.proceed()方法,直到最后一个拦截器,然后将结果返回。

拦截器的责任链模式流程大致如下图所示:

最后

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。

最后针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

需要资料的朋友可以扫描下方二维码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值