OkHttp源码解析(很细 很长)

前言

本文是对OkHttp开源库的一个详细解析,如果你觉得自己不够了解OkHttp,想进一步学习一下,相信本文对你会有所帮助。

本文包含了详细的请求流程分析、各大拦截器解读以及自己的一点反思总结,文章很长,欢迎大家一起交流讨论。


使用方法

使用方法十分简单,分别创建一个OkHttpClient对象,一个Request对象,然后利用他们创建一个Call对象,最后调用同步请求execute()方法或者异步请求enqueue()方法来拿到Response

	private final OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
      .url("https://github.com/")
      .build();
    //同步请求
    Response response = client.newCall(request).execute();
    //todo handle response

    //异步请求
    client.newCall(request).enqueue(new Callback() {
   
      @Override
      public void onFailure(@NotNull Call call, @NotNull IOException e) {
   
		  //todo handle request failed
      }

      @Override
      public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
   
          //todo handle Response
      }
    });

基本对象介绍

正如使用方法中所述,我们先后构建了 OkHttpClient对象、Request对象、Call对象,那这些对象都是什么意思,有什么作用呢?这个就需要我们进一步学习了解了。

OkHttpClient

一个请求的配置类,采用了建造者模式,方便用户配置一些请求参数,如配置callTimeoutcookieinterceptor等等。

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

  constructor() : this(Builder())

  class Builder constructor() {
   
  	//调度器
    internal var dispatcher: Dispatcher = Dispatcher()
    //连接池
    internal var connectionPool: ConnectionPool = ConnectionPool()
    //整体流程拦截器
    internal val interceptors: MutableList<Interceptor> = mutableListOf()
    //网络流程拦截器
    internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
    //流程监听器
    internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
    //连接失败时是否重连
    internal var retryOnConnectionFailure = true
    //服务器认证设置
    internal var authenticator: Authenticator = Authenticator.NONE
    //是否重定向
    internal var followRedirects = true
    //是否从HTTP重定向到HTTPS
    internal var followSslRedirects = true
    //cookie设置
    internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
    //缓存设置
    internal var cache: Cache? = null
    //DNS设置
    internal var dns: Dns = Dns.SYSTEM
    //代理设置
    internal var proxy: Proxy? = null
    //代理选择器设置
    internal var proxySelector: ProxySelector? = null
    //代理服务器认证设置
    internal var proxyAuthenticator: Authenticator = Authenticator.NONE
    //socket配置
    internal var socketFactory: SocketFactory = SocketFactory.getDefault()
    //https socket配置
    internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
    internal var x509TrustManagerOrNull: X509TrustManager? = null
    internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
    //协议
    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
	
···省略代码···

Request

同样是请求参数的配置类,也同样采用了建造者模式,但相比于OkHttpClientRequest就十分简单了,只有四个参数,分别是请求URL请求方法请求头请求体

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 {
   
  	//请求的URL
    internal var url: HttpUrl? = null
    //请求方法,如:GET、POST..
    internal var method: String
    //请求头
    internal var headers: Headers.Builder
    //请求体
    internal var body: RequestBody? = null
  ···省略代码···

Call

请求调用接口,表示这个请求已经准备好可以执行,也可以取消只能执行一次

interface Call : Cloneable {
   
  /** 返回发起此调用的原始请求 */
  fun request(): Request

  /**
   * 同步请求,立即执行。
   * 
   * 抛出两种异常:
   * 1. 请求失败抛出IOException;
   * 2. 如果在执行过一回的前提下再次执行抛出IllegalStateException;*/
  @Throws(IOException::class)
  fun execute(): Response

  /**
   * 异步请求,将请求安排在将来的某个时间点执行。
   * 如果在执行过一回的前提下再次执行抛出IllegalStateException */
  fun enqueue(responseCallback: Callback)

  /** 取消请求。已经完成的请求不能被取消 */
  fun cancel()

  /** 是否已被执行  */
  fun isExecuted(): Boolean

  /** 是否被取消   */
  fun isCanceled(): Boolean

  /** 一个完整Call请求流程的超时时间配置,默认选自[OkHttpClient.Builder.callTimeout] */
  fun timeout(): Timeout

  /** 克隆这个call,创建一个新的相同的Call */
  public override fun clone(): Call

  /** 利用工厂模式来让 OkHttpClient 来创建 Call对象 */
  fun interface Factory {
   
    fun newCall(request: Request): Call
  }
}

RealCall

OkHttpClient 中,我们利用 newCall 方法来创建一个 Call 对象,但从源码中可以看出,newCall 方法返回的是一个 RealCall 对象。

OkHttpClient.kt

override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

RealCallCall接口的具体实现类,是应用端与网络层的连接桥,展示应用端原始的请求与连接数据,以及网络层返回的response及其它数据流。
通过使用方法也可知,创建RealCall对象后,就要调用同步或异步请求方法,所以它里面还包含同步请求 execute()异步请求 enqueue()方法。(后面具体展开分析)

AsyncCall

异步请求调用,是RealCall的一个内部类,就是一个Runnable,被调度器中的线程池所执行。

inner class AsyncCall(
    //用户传入的响应回调方法
    private val responseCallback: Callback
  ) : Runnable {
   
    //同一个域名的请求次数,volatile + AtomicInteger 保证在多线程下及时可见性与原子性
    @Volatile var callsPerHost = AtomicInteger(0)
      private set

    fun reuseCallsPerHostFrom(other: AsyncCall) {
   
      this.callsPerHost = other.callsPerHost
    }

···省略代码···

    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)
        //请求失败,调用 Callback.onFailure() 方法
        responseCallback.onFailure(this@RealCall, ioException)
      } finally {
   
        if (!success) {
   
          //请求失败,调用调度器finish方法
          client.dispatcher.finished(this) // This call is no longer running!
        }
      }
    }

    override fun run() {
   
      threadName("OkHttp ${
     redactedUrl()}") {
   
        var signalledCallback = false
        timeout.enter()
        try {
   
          //请求成功,获取到服务器返回的response
          val response = getResponseWithInterceptorChain()
          signalledCallback = true
          //调用 Callback.onResponse() 方法,将 response 传递出去
          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 {
   
            //请求失败,调用 Callback.onFailure() 方法
            responseCallback.onFailure(this@RealCall, e)
          }
        } catch (t: Throwable) {
   
          //请求出现异常,调用cancel方法来取消请求
          cancel()
          if (!signalledCallback) {
   
            val canceledException = IOException("canceled due to $t")
            canceledException.addSuppressed(t)
            //请求失败,调用 Callback.onFailure() 方法
            responseCallback.onFailure(this@RealCall, canceledException)
          }
          throw t
        } finally {
   
          //请求结束,调用调度器finish方法
          client.dispatcher.finished(this)
        }
      }
    }
  }

Dispatcher

调度器,用来调度Call对象,同时包含线程池与异步请求队列,用来存放与执行AsyncCall对象。

class Dispatcher 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值