OkHttp原理解析之请求流程

本文基于OkHttp4.9.1

关于OkHttp这个东西大家都很熟悉了吧,那么对于它的请求流程你了解吗,你还在停留在知其然而不知其所以然的阶段码。来看一下我对它的理解吧

使用方式

    fun requestTest() {
        val url = "https://www.wanandroid.com/banner/json"
        val client = OkHttpClient();
        val request = Request.Builder()
            .url(url)
            .build()
       //异步请求
        client.newCall(request).enqueue(object : Callback {//1
            override fun onFailure(call: Call, e: IOException) {

            }

            override fun onResponse(call: Call, response: Response) {

            }
        })
        //同步请求
        client.newCall(request).execute()//2
    }

以上代码是OkHttp的基础使用方式,也是我们最方便切入框架结构的代码块。

异步请求

源码阅读选择哪个作为入口呢,当然是最接近功能实现的enqueue()方法了了。进入enqueue()方法发现它是一个抽象方法,它所在的类也是一个接口类。那么只能寻求它的上级实现了,进入newCall()的逻辑看一下

  /** Prepares the [request] to be executed at some point in the future. */
  override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

它是创建了一个RealCall对象。RealCall有三个参数 val client: OkHttpClient、 val originalRequest: Request、 val forWebSocket: Boolean。client负责OkHttp的通用配置,originalRequest负责OkHttp的请求发起,forWebSocket用来判断是否需要以WebSocket形式建立请求连接。既然找到了newCall()创建的对象,那么就可以看一下enqueue()方法的实现了

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

    callStart()//3
    client.dispatcher.enqueue(AsyncCall(responseCallback))//4
  }
  private fun callStart() {
   //跟踪程序,在程序出错时进行错误分析
    this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()")
   //监听反馈
    eventListener.callStart(this)
  }

在RealCall##enqueue()的注释3的主要就是负责程序的错误分析以及流程监听反馈,注释4是enqueue()方法的执行关键,它调用了dispatcher的enqueue()方法并且向其中传入了一个AsyncCall对象。dispatcher是一个Dispatcher对象,Dispatcher类在OkHttp中负责线程的调度处理,功能由ExecutorService实现,有兴趣的同学可以单独去看一下Dispatcher源码。现在看一下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()
    val isRunning: Boolean
    synchronized(this) {
      val i = readyAsyncCalls.iterator()
      while (i.hasNext()) {
        val asyncCall = i.next()

        if (runningAsyncCalls.size >= this.maxRequests) break // 5
        if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue //6

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

    return isRunning
  }

readyAsyncCalls是一个双向队列,负责保存即将运行的AsyncCall对象。promoteAndExecute()中会对readyAsyncCalls进行遍历,将满足条件的AsyncCall对象取出放入executableCalls集合中,executableCalls保存的就是正在执行的AsyncCall对象。条件筛选是注释5及注释6,目的是防止程序过载。筛选完成后会对重新赋值的executableCalls进行遍历,取出其中的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!
        }
      }
    }

AsyncCall##executeOn()核心只有一行executorService.execute(this),通过线程池来执行一个任务。AsyncCall自己实现了Runnable接口,所以只需要看一下AsyncCall##run()方法即可

    override fun run() {
      threadName("OkHttp ${redactedUrl()}") {
        var signalledCallback = false
        timeout.enter()
        try {
          val response = getResponseWithInterceptorChain()
          signalledCallback = true
          responseCallback.onResponse(this@RealCall, response)
        } 
        ......  
        ......      
      }
    }

在AsyncCall##run()其实也只有一行关键代码 val response = getResponseWithInterceptorChain(),拿到请求返回,然后通过responseCallback将结果回传responseCallback就是我们注释1中传入的Callback。如此一个异步请求流程就完成了

同步请求

前文分析异步方法enqueue()实现在RealCall类中,那么同步方法execute()也实现在
RealCall类中。

  override fun execute(): Response {
    check(executed.compareAndSet(false, true)) { "Already Executed" }

    timeout.enter()
    callStart()
    try {
      client.dispatcher.executed(this)
      return getResponseWithInterceptorChain()
    } finally {
      client.dispatcher.finished(this)
    }
  }

直接就是返回了getResponseWithInterceptorChain()的返回结果
至此OkHttp的同步异步调用流程便分析完了。关于getResponseWithInterceptorChain()方法我会在另一篇文章中解析

如果你有什么疑问或者认为哪个地方解析有错误,欢迎您在评论区指正。技术都是交流出来的

你可能感兴趣的:(OkHttp原理解析之请求流程)