OkHttp请求源码分析

OkHttp分为异步请求和同步请求两部分

同步请求

vbscript 复制代码
call.execute()

execute代码如下:

#okhttp3.internal.connection.RealCall

kotlin 复制代码
override fun execute(): Response {
  check(executed.compareAndSet(false, true)) { "Already Executed" }
   
   // 1.开启超时检测
timeout.enter()
  
  callStart()
  try {
      // 2. 将请求添加在同步请求队列
    client.dispatcher.executed(this)
    //3. 调用getResponseWithInterceptorChain获取Response
    return getResponseWithInterceptorChain()
  } finally {
    client.dispatcher.finished(this)
  }
}
  1. 开启超时检测

  2. 将请求添加在同步请求队列

  3. 调用getResponseWithInterceptorChain获取Response

异步请求

okHttpClient.newCall返回值

首先,我们看一下okHttpClient.newCall返回的是什么

vbscript 复制代码
newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

newCall返回一个RealCall对象

call.enqueue的源码

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

   //1.  
callStart()
  //2.
  client.dispatcher.enqueue(AsyncCall(responseCallback))
}
  1. callStart()方法,内部调用的EventListener.callStart,是一个全局监听请求过程的方法
  2. 调用dispatcherenqueue方法,从字面理解为,请求需要排队执行,这里的请求是AsyncCall对象,AsyncCall中包含返回结果的监听responseCallback,也就是我们在调用call.enqueue时传入的callBack

AsyncCall下面会进行具体介绍

Dispatcher的enqueue方法

scss 复制代码
internal fun enqueue(call: AsyncCall) {
  synchronized(this) {
      //1. 
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)
    }
  }
  //2. 
promoteAndExecute()
}

使用同步锁*synchronized*防止线程同步问题:

  1. AsyncCall对象加入readyAsyncCalls这个队列中

  2. promoteAndExecute(),推动并执行,我们看一下具体干了什么

Dispatcher的promoteAndExecute方法

通过注释,我们可以很清楚的知道该函数的作用:

将合法的请求从readyAsyncCalls 队列里移到runningAsyncCalls队列里,并且用ExecutorService执行他们

kotlin 复制代码
 /**
* Promotes eligible calls from [readyAsyncCalls] to [runningAsyncCalls] and runs them on the
* executor service. Must not be called with synchronization because executing calls can call
* into user code.
*
*  @return  true if the dispatcher is currently running calls.
*/
private fun promoteAndExecute(): Boolean {
  this.assertThreadDoesntHoldLock()
   
   //1. 
  val executableCalls = mutableListOf<AsyncCall>()
  val isRunning: Boolean
  synchronized(this) {
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.
       // 从readyAsyncCalls中移除
      i.remove()
      asyncCall.callsPerHost.incrementAndGet()
      //2.  添加到executableCalls/runningAsyncCalls 队列中
      executableCalls.add(asyncCall)
      runningAsyncCalls.add(asyncCall)
    }
    isRunning = runningCallsCount() > 0
  }

// Avoid resubmitting if we can't logically progress
  // particularly because RealCall handles a RejectedExecutionException
  // by executing on the same thread.
  if (executorService.isShutdown) {
      ...
  } else {
    for (i in 0 until executableCalls.size) {
    // 3. 
      val asyncCall = executableCalls[i]
      asyncCall.executeOn(executorService)
    }
  }

  return isRunning
}
  1. 声明一个AsyncCall的集合
  2. 将每个AsynCallreadyAsyncCalls中移除,添加到executableCalls/runningAsyncCalls 队列中
  3. executableCalls中取出AsynCall,调用AsyncCall.executeOn方法,并传入executorService

executorServiceExecutorService对象:

kotlin 复制代码
val executorService: ExecutorService
  get() {
    if (executorServiceOrNull == null) {
      executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
          SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
    }
    return executorServiceOrNull!!
  }
  

ExecutorService是一个没有核心线程,非核心线程数为Int最大值,线程闲置60s会被回收的线程池

AsyncCall.executeOn

kotlin 复制代码
fun executeOn(executorService: ExecutorService) {
  client.dispatcher.assertThreadDoesntHoldLock()

  var success = false
  try {
      //1. 
    executorService.execute(this)
    success = true
  } catch (e: RejectedExecutionException) {
    failRejected(e)
  } finally {
    if (!success) {
      client.dispatcher.finished(this) // This call is no longer running!
    }
  }
}

使用传入的executorService线程池执行AsyncCall任务,而AsyncCall是一个Runnable对象,直接查看其run方法

AsyncCall.run

kotlin 复制代码
override fun run() {
  threadName("OkHttp ${redactedUrl()}") {
var signalledCallback = false
    // 1. 
    timeout.enter()
    try {
    // 2.
      val response = getResponseWithInterceptorChain()
      signalledCallback = true
      // 3. 
      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 {
      //4. 
        responseCallback.onFailure(this@RealCall, e)
      }
    } catch (t: Throwable) {
      cancel()
      if (!signalledCallback) {
        val canceledException = IOException("canceled due to $t")
        canceledException.addSuppressed(t)
        // 5. 
        responseCallback.onFailure(this@RealCall, canceledException)
      }
      throw t
    } finally {
      client.dispatcher.finished(this)
    }
  }
}
  1. 调用timeout.enter()开启超时检测

  2. 调用getResponseWithInterceptorChain获取响应结果

  3. 获取到response后调用responseCallback.response方法

  4. 调用responseCallback.onFailure,失通知败结果

getResponseWithInterceptorChain源码分析

blog.csdn.net/xuwb123xuwb...

ini 复制代码
internal fun getResponseWithInterceptorChain(): Response {
  // Build a full stack of interceptors.
  val interceptors = mutableListOf<Interceptor>()
  interceptors += client.interceptors
  interceptors += RetryAndFollowUpInterceptor(client)
  interceptors += BridgeInterceptor(client.cookieJar)
  interceptors += CacheInterceptor(client.cache)
  interceptors += ConnectInterceptor
  if (!forWebSocket) {
    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 {
    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)
    }
  }
}

简单来说,getResponseWithInterceptorChain方法中,就是构建一个链式拦截器,然后发起请求,整个过程是通过拦截器的链式调用完成的,即先从左到右调用,再从右到左返回结果

暂时无法在飞书文档外展示此内容

  • RetryAndFollowUpInterceptor:负责失败重试和重定向

  • BridgeInterceptor:负责把用户请求转换为发送到服务器的请求,并把服务器的响应转化为用户需要的响应

  • CacheInterceptor:负责读取缓存、更新缓存

  • ConnectInterceptor:负责和服务器建立连接

  • CallServerInterceptor:负责向服务器发送数据,从服务器读取响应数据

addInterceptor 和 addNetworkInterceptor区别

getResponseWithInterceptorChain方法中可以看到:拦截器是通过责任链模式调用的,

addInterceptor添加的Interceptor会被添加到责任链的开端,因此:

  • 任何情况下都会首先执行

  • 不受重定向和重试机制的影响,即自定义拦截器只会被执行一次

addNetworkInterceptor添加的拦截器处在ConnectInterceptor之后,因此:

  • 如果无网连接失败,该拦截器不会被调用
  • 重定向和重试几次,该拦截器就会被调用几次
  • 允许操作中间响应,比如当请求操作发生重定向(拦截被执行了两次)或者重试等。
  • 不允许调用缓存来short-circuit (短路)这个请求。(意思就是说不能从缓存池中获取缓存对象返回给客户端,必须通过请求服务的方式获取响应,也就是Chain.proceed())
  • 可以监听数据的传输
相关推荐
Elieal19 小时前
AJAX 知识
前端·ajax·okhttp
咖啡の猫4 天前
Vue 实例生命周期
前端·vue.js·okhttp
Jeled7 天前
Retrofit 与 OkHttp 全面解析与实战使用(含封装示例)
android·okhttp·android studio·retrofit
Jeled8 天前
Android 网络层最佳实践:Retrofit + OkHttp 封装与实战
android·okhttp·kotlin·android studio·retrofit
allk5510 天前
OkHttp源码解析(一)
android·okhttp
allk5510 天前
OkHttp源码解析(二)
android·okhttp
aFakeProgramer10 天前
拆分PDF.html 办公小工具
okhttp
一壶浊酒..12 天前
ajax局部更新
前端·ajax·okhttp
洛克大航海15 天前
Ajax基本使用
java·javascript·ajax·okhttp
whltaoin21 天前
Java 网络请求 Jar 包选型指南:从基础到实战
java·http·okhttp·网络请求·retrofit