OKhttp 源码解析(一)

OKhttp 源码解析(一)

这一期我们先从 Okhttp 发送求情 到 收到响应这个过程的主体框架进行的了解,后面几期在逐步深入源码细节。让我们一起来学习吧(~ _ ~)!
Okhttp 从4.0开始都逐步换成Kotlin ,所以我们看的源码也都用Kotlin吧)

OKhttp地址

友情提醒:大家阅读源码的时候,最好是从使用场景出发,从你熟悉的 API 进入源码,有目的性的去逐步了解内部实现原理。先扫清主线粗略的了解,在去深入细节(否则,会不断的进入新的细节就迷路了,别问我是怎么知道的 555~~)

示例代码
    val client = OkHttpClient()
    val url = "https://www.baidu.com/"

    @Throws(IOException::class)
    fun run(url: String): String? {
        val request: Request = Request.Builder()
            .url(url)
            .build()
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: java.io.IOException) {

            }
            override fun onResponse(call: Call, response: Response) {
                println("Response status code :${response.code}")
                Log.i("ResponseCode", response.code.toString())
            }
        })
        return ""
    }
最常用的就是 enqueue 方法. execute 用的比较少
进入 enqueue 发现它是 Call 接口种的 一个抽象方法
interface Call : Cloneable {
  ...
fun enqueue(responseCallback: Callback)
  
@Throws(IOException::class)
fun execute(): Response
  ...

那么往前找去看 newCall 这个方法,它的返回值Call 是 一个叫RealCall的构造方法
  /** Prepares the [request] to be executed at some point in the future. */
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
进入RealCall 看 ,

有三个构造参数

val client: OkHttpClient 大管家的角色,各种通用配置,如控制链接超时时间 等

val originalRequest: Request, 里面包含了请求信息,get/post,请求header,body 等

val forWebSocket: Boolean WebSocket 全双工通信,服务端与各户端的长连接

class RealCall(
  val client: OkHttpClient,
  /** The application's original request unadulterated by redirects or auth headers. */
  val originalRequest: Request,
  val forWebSocket: Boolean
) : Call {
  private val connectionPool: RealConnectionPool = client.connectionPool.delegate

  private val eventListener: EventListener = client.eventListenerFactory.create(this)

  private val timeout = object : AsyncTimeout() {
    override fun timedOut() {
      cancel()
    }
  }.apply {
    timeout(client.callTimeoutMillis.toLong(), MILLISECONDS)
  }
  
  ------
    override fun enqueue(responseCallback: Callback) {
    synchronized(this) {
      check(!executed) { "Already Executed" }
      executed = true
    }
    callStart() // 主要做请求的过程中的事件记录(分析问题用的)
    client.dispatcher.enqueue(AsyncCall(responseCallback)) // 主要看这一句
  }
接下来看 RelCall 的 enqueue 方法

client.dispatcher.enqueue(AsyncCall(responseCallback)) // 主要看这一句

调用了 client.dispatcher 的 enqueue
  • Dispatcher 线程调度 (同时有多个请求,通过它来完成)

    • 内部使用Java 的 线程池来处理 ExecutorService (将请求切换到后台线程)

    • maxRequests (最大请求数64 ) maxRequestsPerHost(同一主机最大请求数5)

    • 注意 maxRequests 和 maxRequestsPerHost 这俩个参数 都是可以被 set 的~~

  • dispatcher.enqueue (call: AsyncCall)

      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) {
            // 用来记录 maxRequestsPerHost 数量的
            val existingCall = findExistingCallWithHost(call.host)  
            if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
          }
        }
        promoteAndExecute()
      }
    
    • 将call 加入了一个 双向队列 readyAsyncCalls.add(call) (存放了准备要执行,还没执行的请求)

    • 在看 promoteAndExecute() 方法

    主要作用促进,将准备中的任务(readyAsyncCalls),放入执行任务队列(runningAsyncCalls),但 runningAsyncCalls 知识起一个标记作用,
    最后要执行人任务的是 executableCalls ;
    for (i in 0 until executableCalls.size) {
    val asyncCall = executableCalls[i]
    asyncCall.executeOn(executorService)
    }

      private fun promoteAndExecute(): Boolean {
        this.assertThreadDoesntHoldLock()
    
        val executableCalls = mutableListOf<AsyncCall>()
        val isRunning: Boolean
        synchronized(this) {
          val i = readyAsyncCalls.iterator()  // 1 在这里遍历出来
          while (i.hasNext()) {
            val asyncCall = i.next()
    
            //2 在这里筛选 可执行的 call
            if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
            if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
            i.remove()
            asyncCall.callsPerHost.incrementAndGet()
            //3 将可执行的 call 放入 executableCalls 和 runningAsyncCalls
            executableCalls.add(asyncCall)
            runningAsyncCalls.add(asyncCall)
          }
          isRunning = runningCallsCount() > 0
        }
    		//4 在遍历 executableCalls 挨个去执行
        for (i in 0 until executableCalls.size) {
          val asyncCall = executableCalls[i]
          asyncCall.executeOn(executorService)
        }
        return isRunning
      }
    
    
  • 重点来了 通过 asyncCall.executeOn(executorService) 挨个去执行

    • 了解了 executeOn() 也就了解了整个执行过程对吧!

    先来看 executorService 的这个入参 , 他是一个单一线程队列(马上就会执行)

      if (executorServiceOrNull == null) {
        executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
            SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
      }
    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!
        }
      }
    }
  • executorService.execute(this) 入参是 Runnble 但是传入一个 this ,说明当前类 AsyncCall 实现了Runnable 接口! 我们就直接去看它是怎样重写的 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 {
              client.dispatcher.finished(this)
            }
          }
        }
    
  • 在run 方法中我们见到了 熟悉的 responseCallback.onResponse()responseCallback. onFailure() 这两个回调方法,对应的就是第一段 示例代码中的 **onResponse()**和 onFailure() ,是不是感觉很亲切了呢!~

那么到这里整个 Okhttp的请求到响应的主体框架就闭环了,

与此同时,我们也发现 getResponseWithInterceptorChain() 返回了响应值,但是目前还没看到请求的执行的过程,那么也就说明 getResponseWithInterceptorChain() 包含了所有请求的具体过程,整个请求的核心方法 ,其内部使用 责任链模式 将整个工作的流程串了起来,这个我们后面再将!

下一期会深入源码细节在探索Okhttp!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值