美文网首页
通过使用方式逐步理解okhttp源码一

通过使用方式逐步理解okhttp源码一

作者: 浮游生物的幻想 | 来源:发表于2020-04-23 18:39 被阅读0次

从okhttp最基本的使用方式解析okhttp

okhttp的使用很简单

  • 导入依赖 implementation 'com.squareup.okhttp3:okhttp:4.5.0'使用的是4.x跟3.x版本相比代码已经转变为kotlin
  • new OkHttpClient;
  • 构造Request对象;
  • 通过前两步中的对象构建Call对象;
  • 通过Call.enqueue(Callback)方法来提交异步请求;
 val mOk = OkHttpClient()
        val request = Request.Builder()
            .url("请求地址")
            .get()//请求方式
            .build()
        val call = mOk.newCall(request)
        call.enqueue(object : Callback {
            override fun onResponse(call: Call, response: Response) {
                Log.e(TAG, "请求成功")
            }

            override fun onFailure(call: Call, e: IOException) {
                Log.e(TAG, "请求失败")
            }
        })

步骤一:创建okhttpClicent实例

val mOk = OkHttpClient()
okhttp在这一步内进行了很多的默认配置,都在OkHttpClient()构造方法内的Builder()对象中,如连接超时,读取超时,写入超时,请求协议,重连,缓存等,所以如果要配置这些的话就要通过OkHttpClient.Builder()来构建OkhttpClient()对象。如果没有特别要求,使用默认的就可以,一句代码就搞定,使用起来是很方便的(●ˇ∀ˇ●)

 class Builder constructor() {
   //调度器
    internal var dispatcher: Dispatcher = Dispatcher()
   //连接池管理HTTP和HTTP/2连接的重用以减少网络延迟
    internal var connectionPool: ConnectionPool = ConnectionPool()
   //存储拦截器实例,本质责任链模式
    internal val interceptors: MutableList<Interceptor> = mutableListOf()
    internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
   //事件侦听器工厂 监听http通信
    internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
   //允许失败重连
    internal var retryOnConnectionFailure = true
    internal var authenticator: Authenticator = Authenticator.NONE
   //允许重定向
    internal var followRedirects = true
   //是否允许 SSL 重定向
    internal var followSslRedirects = true
   //存储cookie 不设置则不存储 cookie。
    internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
   //缓存
    internal var cache: Cache? = null
    internal var dns: Dns = Dns.SYSTEM
    internal var proxy: Proxy? = null
    internal var proxySelector: ProxySelector? = null
    internal var proxyAuthenticator: Authenticator = Authenticator.NONE
    internal var socketFactory: SocketFactory = SocketFactory.getDefault()
    internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
    internal var x509TrustManagerOrNull: X509TrustManager? = null
    internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
   //请求协议   internal val DEFAULT_PROTOCOLS = immutableListOf(HTTP_2, HTTP_1_1)
    internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
    internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
    internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
    internal var certificateChainCleaner: CertificateChainCleaner? = null
  //调度超时时间
    internal var callTimeout = 0
  //连接超时时间
    internal var connectTimeout = 10_000
  //读取超时时间
    internal var readTimeout = 10_000
   //写入超时时间
    internal var writeTimeout = 10_000
    internal var pingInterval = 0
    internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
    internal var routeDatabase: RouteDatabase? = null

在OkhttpClick构造方法内有一个调度器,主要有①并发执行的最大请求数②每个主机并发请求的最大数③有一个线程池,这个线程池内理论上允许的线程数是不受限制的,空闲线程超过60秒会自动被回收,线程池为了解决执行大量异步任务时,减少每个任务的调用开销,所提供的一种限制和管理资源的方法 ④调度器内还定义了三个队列两个异步一个同步

 /**
   * 并发执行的最大请求数
   */
  @get:Synchronized var maxRequests = 64
    set(maxRequests) {
      require(maxRequests >= 1) { "max < 1: $maxRequests" }
      synchronized(this) {
        field = maxRequests
      }
      promoteAndExecute()
    }

  /**
   * 每个主机并发执行的最大请求数
   */
  @get:Synchronized var maxRequestsPerHost = 5
    set(maxRequestsPerHost) {
      require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" }
      synchronized(this) {
        field = maxRequestsPerHost
      }
      promoteAndExecute()
    }

  private var executorServiceOrNull: ExecutorService? = null

  @get:Synchronized
  @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!!
    }

 /**按运行顺序准备异步调用 */
  private val readyAsyncCalls = ArrayDeque<AsyncCall>()

  /** 正在运行异步调用。 */
  private val runningAsyncCalls = ArrayDeque<AsyncCall>()

  /** 运行的同步调用。 */
  private val runningSyncCalls = ArrayDeque<RealCall>()

构造方法内还有一个连接池internal var connectionPool: ConnectionPool = ConnectionPool(),主要作用是管理HTTP和HTTP/2连接的重用以减少网络延迟,实现了多路复用,这也是okhttp的特点之一,目前默认是允许5个空闲连接数

/**一个参数最大空闲连接数,第二个参数保留连接时间,第三个时间单位*/
  constructor() : this(5, 5, TimeUnit.MINUTES)

步骤二:构造Request对象

 val request = Request.Builder()
            .url("请求地址")
            .get()//请求方式
            .build()

Request内主要是决定了请求地址,请求方式(post,get等),请求头,请求体,比较好理解。只贴关键代码

class Request internal constructor(
  @get:JvmName("url") val url: HttpUrl,
  @get:JvmName("method") val method: String,
  @get:JvmName("headers") val headers: Headers,
  @get:JvmName("body") val body: RequestBody?,
  internal val tags: Map<Class<*>, Any>
) {
 open class Builder {
    internal var url: HttpUrl? = null
    internal var method: String
    internal var headers: Headers.Builder
    internal var body: RequestBody? = null

    constructor() {
  //默认是“GET”请求
      this.method = "GET"
      this.headers = Headers.Builder()
    }

    /**
     * 设置URL,如果URL无效时会返回空
     */
    open fun url(url: String): Builder {
      // Silently replace web socket URLs with HTTP URLs.
      val finalUrl: String = when {
        url.startsWith("ws:", ignoreCase = true) -> {
          "http:${url.substring(3)}"
        }
        url.startsWith("wss:", ignoreCase = true) -> {
          "https:${url.substring(4)}"
        }
        else -> url
      }
      return url(finalUrl.toHttpUrl())
     /**@JvmStatic
        @JvmName("get") fun String.toHttpUrl(): HttpUrl = Builder().parse(null, this).build()*/
    }

    /**
     *设置请求头
     */
    open fun header(name: String, value: String) = apply {
      headers[name] = value
    }

    open fun addHeader(name: String, value: String) = apply {
      headers.add(name, value)
    }

    /** 删除请求头 */
    open fun removeHeader(name: String) = apply {
      headers.removeAll(name)
    }

    /**
     * 设置缓存
     */
    open fun cacheControl(cacheControl: CacheControl): Builder {
      val value = cacheControl.toString()
      return when {
        value.isEmpty() -> removeHeader("Cache-Control")
        else -> header("Cache-Control", value)
      }
    }

   //各种请求方式
    open fun get() = method("GET", null)
    open fun post(body: RequestBody) = method("POST", body)
  //...
 //构建Request
    open fun build(): Request {
      return Request(
          checkNotNull(url) { "url == null" },
          method,
          headers.build(),
          body,
          tags.toImmutableMap()
      )
    }
  }

可以看到在构造方法内Okhttp存在默认“GET”请求方式,所以这个可以忽略不写。

步骤三:通过OkHttpClient和Request构造Call对象

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

通过上面两段代码看到,okhttp的整个网络请求处理都是通过RealCall来进行的,是OkHttp应用程序和网络层之间的桥梁。看RealCall的关键代码

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
//监听http通信
  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 execute(): Response {
    synchronized(this) {
      check(!executed) { "Already Executed" }
      executed = true
    }
    timeout.enter()
    callStart()
    try {
      client.dispatcher.executed(this)
      return getResponseWithInterceptorChain()
    } finally {
      client.dispatcher.finished(this)
    }
  }
//异步请求
  override fun enqueue(responseCallback: Callback) {
    synchronized(this) {
      check(!executed) { "Already Executed" }
      executed = true
    }
    callStart()
    client.dispatcher.enqueue(AsyncCall(responseCallback))
  }

//完整的拦截器堆栈
  @Throws(IOException::class)
  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
    )
//...
拦截链的调用
   val response = chain.proceed(originalRequest)
//...
  }

RealCall类中对网络的连接、请求、响应进行了处理,并且建立了完整的拦截器链是重要组成部分,拦截链的调用

/**
 *承载整个拦截器链的具体拦截器链:所有应用程序
 *拦截器、OkHttp核心、所有网络拦截器,最后是网络调用者。
 */
  @Throws(IOException::class)
  override fun proceed(request: Request): Response {
   //检查机制
    check(index < interceptors.size)

    calls++

    if (exchange != null) {
      check(exchange.finder.sameHostAndPort(request.url)) {
        "network interceptor ${interceptors[index - 1]} must retain the same host and port"
      }
      check(calls == 1) {
        "network interceptor ${interceptors[index - 1]} must call proceed() exactly once"
      }
    }

    // 调用链中的下一个拦截器
    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
  }

这块儿代码说明了拦截器的调用是根据添加到 interceptors 集合的顺序,逐个往下调用拦截器(关于各个拦截器的具体作用,嗯~ o( ̄▽ ̄)o,随后再说)

最后一步发起请求

发动网络请求会调RealCall类中的同步 execute() or异步方法 enqueue(responseCallback: Callback) 也就是

    call.enqueue(object : Callback {
            override fun onResponse(call: Call, response: Response) {
                Log.e(TAG, "请求成功")
            }

            override fun onFailure(call: Call, e: IOException) {
                Log.e(TAG, "请求失败")
            }
        })

至此,最简单的okhttp网络请求流程结束

相关文章

网友评论

      本文标题:通过使用方式逐步理解okhttp源码一

      本文链接:https://www.haomeiwen.com/subject/okraihtx.html