Kotlin1.3 OkHttp3 inteceptor源码学习(一)

常见OkHttp初始化代码

     var okHttpClient = OkHttpClient.Builder()
            .readTimeout(readTimeout.toLong(), TimeUnit.MILLISECONDS)
            .connectTimeout(connectTimeOut.toLong(), TimeUnit.MILLISECONDS)
            .addInterceptor(tokenInterceptor)
            .addInterceptor(logInterceptor)
            .addInterceptor(mRewriteCacheControlInterceptor)
            .addNetworkInterceptor(mRewriteCacheControlInterceptor)
            .addInterceptor(headerInterceptor)
            .addInterceptor(basicParamsInterceptor)
            .cache(cache)
            .build()

从代码的源头OkHttpClient的声明开始看,OkHttpClient实现了Call和WebSocket两个接口内的工厂接口Factory
以及java本身的Cloneable接口

open class OkHttpClient internal constructor(
  builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {

OkHttp的内部实现用到了Builder模式。
内部类Builder持有一个MutableList,存储着接口Interceptor的实现类

class Builder constructor() {
    internal val interceptors: MutableList<Interceptor> = mutableListOf()

OkHttpClient.Builder()方法创建了OkHttpClient.Builder的实例,addInterceptor(interceptor: Interceptor)传入
okhttp3.Interceptor接口类型的实现类,方法内部通过 kotlin语法中的apply {+=interceptor}将传入的interceptor添加到成员变量 interceptors的MutableList 中。

  fun addInterceptor(interceptor: Interceptor) = apply {
      interceptors += interceptor
    }

通过OKHttp发送请求

        val request = Request.Builder().url("http://www.baidu.com").build()
        okHttpClient.newCall(request).execute()

Request.Builder.build()最终返回的Request类型实例

open fun build(): Request {
      return Request(
          checkNotNull(url) { "url == null" },
          method,
          headers.build(),
          body,
          tags.toImmutableMap()
      )
    }
  }

HttpClient中 newCall方法的调用

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

OkHttpClient.newCall方法返回了Call类型的实例,看到这里应该看一下Call是什么

/**
 * A call is a request that has been prepared for execution. A call can be canceled. As this object
 * represents a single request/response pair (stream), it cannot be executed twice.
 */
interface Call : Cloneable {
  /** Returns the original request that initiated this call. */
  fun request(): Request

  /**
   * Invokes the request immediately, and blocks until the response can be processed or is in error.
   *
   * To avoid leaking resources callers should close the [Response] which in turn will close the
   * underlying [ResponseBody].
   *
   * ```
   * // ensure the response (and underlying response body) is closed
   * try (Response response = client.newCall(request).execute()) {
   *   ...
   * }
   * ```
   *
   * The caller may read the response body with the response's [Response.body] method. To avoid
   * leaking resources callers must [close the response body][ResponseBody] or the response.
   *
   * Note that transport-layer success (receiving a HTTP response code, headers and body) does not
   * necessarily indicate application-layer success: `response` may still indicate an unhappy HTTP
   * response code like 404 or 500.
   *
   * @throws IOException if the request could not be executed due to cancellation, a connectivity
   *     problem or timeout. Because networks can fail during an exchange, it is possible that the
   *     remote server accepted the request before the failure.
   * @throws IllegalStateException when the call has already been executed.
   */
  @Throws(IOException::class)
  fun execute(): Response

  /**
   * Schedules the request to be executed at some point in the future.
   *
   * The [dispatcher][OkHttpClient.dispatcher] defines when the request will run: usually
   * immediately unless there are several other requests currently being executed.
   *
   * This client will later call back `responseCallback` with either an HTTP response or a failure
   * exception.
   *
   * @throws IllegalStateException when the call has already been executed.
   */
  fun enqueue(responseCallback: Callback)

  /** Cancels the request, if possible. Requests that are already complete cannot be canceled. */
  fun cancel()

  /**
   * Returns true if this call has been either [executed][execute] or [enqueued][enqueue]. It is an
   * error to execute a call more than once.
   */
  fun isExecuted(): Boolean

  fun isCanceled(): Boolean

  /**
   * Returns a timeout that spans the entire call: resolving DNS, connecting, writing the request
   * body, server processing, and reading the response body. If the call requires redirects or
   * retries all must complete within one timeout period.
   *
   * Configure the client's default timeout with [OkHttpClient.Builder.callTimeout].
   */
  fun timeout(): Timeout

  /**
   * Create a new, identical call to this one which can be enqueued or executed even if this call
   * has already been.
   */
  public override fun clone(): Call

  interface Factory {
    fun newCall(request: Request): Call
  }
}

可以看到Call是一个接口,里面有做request(),execute(),enqueue(responseCallback: Callback)等方法,
不难看出enqueue中传入了一个callback,所以enqueue应该是一个异步请求的形式,那么相对的execute()
就是同步了

companion object {
    fun newRealCall(
      client: OkHttpClient,
      originalRequest: Request,
      forWebSocket: Boolean
    ): RealCall {
      // Safely publish the Call instance to the EventListener.
      return RealCall(client, originalRequest, forWebSocket).apply {
        transmitter = Transmitter(client, this)
      }
    }
  }

那么再回头看HttpClient中的newCall()方法,Call实例真正来自RealCall类中的newRealCall()
说明HttpClient.newCall实际是生成了一个Call接口的实现类RealCall

HttpClient.newCall实际上做的是对RealCall进行初始化

internal class RealCall private constructor(
  val client: OkHttpClient,
  /** The application's original request unadulterated by redirects or auth headers. */
  val originalRequest: Request,
  val forWebSocket: Boolean
) : Call {
  /**
   * There is a cycle between the [Call] and [Transmitter] that makes this awkward.
   * This is set after immediately after creating the call instance.
   */
  private lateinit var transmitter: Transmitter

再看一下Transmitter是什么

/**
 * Bridge between OkHttp's application and network layers. This class exposes high-level application
 * layer primitives: connections, requests, responses, and streams.
 *
 * This class supports [asynchronous canceling][cancel]. This is intended to have the smallest
 * blast radius possible. If an HTTP/2 stream is active, canceling will cancel that stream but not
 * the other streams sharing its connection. But if the TLS handshake is still in progress then
 * canceling may break the entire connection.
 */
class Transmitter(
  private val client: OkHttpClient,
  private val call: Call
) {

transmitter
英 [trænz’mɪtə; trɑːnz-; -ns-] 美 [træns’mɪtɚ]
n. [电讯] 发射机,[通信] 发报机;传达人

结合单词的意思和注释可以知道transmitter是OkHttp中去处理连接、请求、响应和流的一个类,支持一步取消和取消

所以还得往下看Call类做了什么。
点进Call的代码中可以看到Call是一个接口

所以OkHttpClient.newCall.execute()调用的是RealCall类的execute()方法,

 override fun execute(): Response {
    synchronized(this) {
      check(!executed) { "Already Executed" }
      executed = true
    }
    transmitter.timeoutEnter()
    transmitter.callStart()
    try {
      client.dispatcher.executed(this)
      return getResponseWithInterceptorChain()
    } finally {
      client.dispatcher.finished(this)
    }
  }

通过方法名可知getResponseWithInterceptorChain()是真正得到响应后传给初始化的MutableList inteceptors顺序去处理的方法,现在暂时不刨根问底研究其中更深的细节,先了解一下intecepor

@Throws(IOException::class)
  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(interceptors, transmitter, null, 0, originalRequest, this,
        client.connectTimeoutMillis, client.readTimeoutMillis, client.writeTimeoutMillis)

    var calledNoMoreExchanges = false
    try {
      val response = chain.proceed(originalRequest)
      if (transmitter.isCanceled) {
        response.closeQuietly()
        throw IOException("Canceled")
      }
      return response
    } catch (e: IOException) {
      calledNoMoreExchanges = true
      throw transmitter.noMoreExchanges(e) as Throwable
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null)
      }
    }
  }

聚焦到这段代码

val chain = RealInterceptorChain(interceptors, transmitter, null, 0, originalRequest, this,
client.connectTimeoutMillis, client.readTimeoutMillis, client.writeTimeoutMillis)

class RealInterceptorChain(
  private val interceptors: List<Interceptor>,
  private val transmitter: Transmitter,
  private val exchange: Exchange?,
  private val index: Int,
  private val request: Request,
  private val call: Call,
  private val connectTimeout: Int,
  private val readTimeout: Int,
  private val writeTimeout: Int
) : Interceptor.Chain {

接着看Interceptor.Chain发现比较熟悉,

/**
 * Observes, modifies, and potentially short-circuits requests going out and the corresponding
 * responses coming back in. Typically interceptors add, remove, or transform headers on the request
 * or response.
 */
interface Interceptor {
  @Throws(IOException::class)
  fun intercept(chain: Chain): Response

  companion object {
    /**
     * Constructs an interceptor for a lambda. This compact syntax is most useful for inline
     * interceptors.
     *
     * ```
     * val interceptor = Interceptor { chain: Interceptor.Chain ->
     *     chain.proceed(chain.request())
     * }
     * ```
     */
    inline operator fun invoke(crossinline block: (chain: Chain) -> Response): Interceptor =
        object : Interceptor {
          override fun intercept(chain: Chain) = block(chain)
        }
  }

  interface Chain {
    fun request(): Request

    @Throws(IOException::class)
    fun proceed(request: Request): Response

    /**
     * Returns the connection the request will be executed on. This is only available in the chains
     * of network interceptors; for application interceptors this is always null.
     */
    fun connection(): Connection?

    fun call(): Call

    fun connectTimeoutMillis(): Int

    fun withConnectTimeout(timeout: Int, unit: TimeUnit): Chain

    fun readTimeoutMillis(): Int

    fun withReadTimeout(timeout: Int, unit: TimeUnit): Chain

    fun writeTimeoutMillis(): Int

    fun withWriteTimeout(timeout: Int, unit: TimeUnit): Chain
  }
}

不难发现RealInteceptorChain正是OkHttp请求成功后真正的InteceptorChain

@Throws(IOException::class)
  fun proceed(request: Request, transmitter: Transmitter, exchange: Exchange?): Response {
    if (index >= interceptors.size) throw AssertionError()

    calls++

    // If we already have a stream, confirm that the incoming request will use it.
    check(this.exchange == null || this.exchange.connection()!!.supportsUrl(request.url)) {
      "network interceptor ${interceptors[index - 1]} must retain the same host and port"
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    check(this.exchange == null || calls <= 1) {
      "network interceptor ${interceptors[index - 1]} must call proceed() exactly once"
    }

    // Call the next interceptor in the chain.
    val next = RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout)
    val interceptor = interceptors[index]

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

    // Confirm that the next interceptor made its required call to chain.proceed().
    check(exchange == null || 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
  }

留意到这段代码

  // Call the next interceptor in the chain.
    val next = RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout)
    val interceptor = interceptors[index]
    
   @Suppress("USELESS_ELVIS")
    val response = interceptor.intercept(next) ?: throw NullPointerException(
        "interceptor $interceptor returned null")
        
  // Confirm that the next interceptor made its required call to chain.proceed().
    check(exchange == null || index + 1 >= interceptors.size || next.calls == 1) {
      "network interceptor $interceptor must call proceed() exactly once"
    }

根据平时使用OkHttp interceptor的经验拦截器会根据添加的顺序依次拦截,对应的就是这几行代码,
interceptor代表当前拦截器,next为下一个拦截器链的下一环,再看一下HttpLoggingInterceptor的intercept(chain: Interceptor.Chain)方法,中间有一行代码

response = chain.proceed(request)

这段代码可以在大多数拦截器中看到,不难发现这正是Java责任链模式的一个应用场景
不难从Inteceptor接口的注释中看到端倪

/**
 * Observes, modifies, and potentially short-circuits requests going out and the corresponding
 * responses coming back in. Typically interceptors add, remove, or transform headers on the request
 * or response.
 */
interface Interceptor {
  @Throws(IOException::class)
  fun intercept(chain: Chain): Response

  companion object {
    /**
     * Constructs an interceptor for a lambda. This compact syntax is most useful for inline
     * interceptors.
     *
     * ```
     * val interceptor = Interceptor { chain: Interceptor.Chain ->
     *     chain.proceed(chain.request())
     * }
     * ```
     */
    inline operator fun invoke(crossinline block: (chain: Chain) -> Response): Interceptor =
        object : Interceptor {
          override fun intercept(chain: Chain) = block(chain)
        }
  }

所以 这行代码最后会执行chain.proceed(chain.request())

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

也就是RealInteceptor中的process(request: Request)这个方法,而这个方法调用的又是interceptor.intercept(next)
所在的方法,个人理解这是一种递归调用。直到response 被处理

 override fun proceed(request: Request): Response {
    return proceed(request, transmitter, exchange)
  }

你可能感兴趣的:(知识点归纳,OkHttp,Kotlin1.3)