OkHttp3源码分析

1、首先获取OkhttpClient对象和OkHttpClient.Builder,其中有两种方式

   第一种:

OkHttpClient okHttpClient = new OkHttpClient();
OkHttpClient.Builder builder = okHttpClient.newBuilder();
builder.connectTimeout(30, TimeUnit.SECONDS); //连接超时时间
builder.readTimeout(30, TimeUnit.SECONDS); //读数据超时时间
第二种:
 OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
builder.connectTimeout(30, TimeUnit.SECONDS); //连接超时时间 
builder.readTimeout(30, TimeUnit.SECONDS); //读数据超时时间 
OkHttpClient okHttpClient = builder.build();

在new OkhttpClient的时候已经new Builder(),并且进行了初始化默认配置,其下源码基于Kotlin语言如下:

class Builder constructor() {
    internal var dispatcher: Dispatcher = Dispatcher()
    internal var proxy: Proxy? = null
    internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
    internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
    internal val interceptors: MutableList<Interceptor> = mutableListOf()
    internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
    internal var eventListenerFactory: EventListener.Factory = Util.eventListenerFactory(
        EventListener.NONE)
    internal var proxySelector: ProxySelector = ProxySelector.getDefault() ?: NullProxySelector()
    internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
    internal var cache: Cache? = null
    internal var internalCache: InternalCache? = null
    internal var socketFactory: SocketFactory = SocketFactory.getDefault()
    internal var sslSocketFactory: SSLSocketFactory? = null
    internal var certificateChainCleaner: CertificateChainCleaner? = null
    internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
    internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
    internal var proxyAuthenticator: Authenticator = Authenticator.NONE
    internal var authenticator: Authenticator = Authenticator.NONE
    internal var connectionPool: ConnectionPool = ConnectionPool()
    internal var dns: Dns = Dns.SYSTEM
    internal var followSslRedirects: Boolean = true
    internal var followRedirects: Boolean = true
    internal var retryOnConnectionFailure: Boolean = true
    internal var callTimeout: Int = 0
    internal var connectTimeout: Int = 10000
    internal var readTimeout: Int = 10000
    internal var writeTimeout: Int = 10000
    internal var pingInterval: Int = 0

    internal constructor(okHttpClient: OkHttpClient) : this() {
      this.dispatcher = okHttpClient.dispatcher
      this.proxy = okHttpClient.proxy
      this.protocols = okHttpClient.protocols
      this.connectionSpecs = okHttpClient.connectionSpecs
      this.interceptors += okHttpClient.interceptors
      this.networkInterceptors += okHttpClient.networkInterceptors
      this.eventListenerFactory = okHttpClient.eventListenerFactory
      this.proxySelector = okHttpClient.proxySelector
      this.cookieJar = okHttpClient.cookieJar
      this.internalCache = okHttpClient.internalCache
      this.cache = okHttpClient.cache
      this.socketFactory = okHttpClient.socketFactory
      this.sslSocketFactory = okHttpClient.sslSocketFactory
      this.certificateChainCleaner = okHttpClient.certificateChainCleaner
      this.hostnameVerifier = okHttpClient.hostnameVerifier
      this.certificatePinner = okHttpClient.certificatePinner
      this.proxyAuthenticator = okHttpClient.proxyAuthenticator
      this.authenticator = okHttpClient.authenticator
      this.connectionPool = okHttpClient.connectionPool
      this.dns = okHttpClient.dns
      this.followSslRedirects = okHttpClient.followSslRedirects
      this.followRedirects = okHttpClient.followRedirects
      this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure
      this.callTimeout = okHttpClient.callTimeout
      this.connectTimeout = okHttpClient.connectTimeout
      this.readTimeout = okHttpClient.readTimeout
      this.writeTimeout = okHttpClient.writeTimeout
      this.pingInterval = okHttpClient.pingInterval
    }

  解析:默认设置中很多参数也不需要理解,大概知道如下就可以了:

  Dispatcher是保存同步和异步Call的地方,并负责执行异步AsyncCall。

  protocols:默认支持的Http协议版本,其声明默认为HTTP_2、HTTP_1_1

internal val DEFAULT_PROTOCOLS = Util.immutableList(HTTP_2, HTTP_1_1)

  connectionSpecs:Okhttp连接配置,

internal val DEFAULT_CONNECTION_SPECS = Util.immutableList( 
ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT)
@JvmField 
val MODERN_TLS = Builder(true) 
.cipherSuites(*APPROVED_CIPHER_SUITES) 
.tlsVersions(TlsVersion.TLS_1_3, TlsVersion.TLS_1_2) 
.supportsTlsExtensions(true) 
.build()

 connectTimeout连接超时时间

 readTimeout 读数据连接超时时间

 hostnameVerifier、 certificatePinner、 proxyAuthenticator、 authenticator:安全相关的设置;例如进行HTTPS协议的时候,需 要设置SLL证书等安全设置

2、获取Requet对象和Request.Builder()

    

 Request request = new Request.Builder().url(url).
post(requestBody).addHeader("Connection", "close").build(); 

 3、用okhttpClient和request创建一个Call对象

 Call call = okHttpClient.newCall(request);

  4、call进行同步或者异步调用

      4.1、同步调用 调用execute方法     

 Call call = okHttpClient.newCall(request);
        try {
            call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }

    同步调用源码分析:

 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)
    }
  }

 /** Used by `Call#execute` to signal it is in-flight. */
  @Synchronized internal fun executed(call: RealCall) {
    runningSyncCalls.add(call)
  }

将该任务加入runningSyncCalls正在运行执行的任务队列中

 2、异步调用

    

override fun enqueue(responseCallback: Callback) {
    synchronized(this) {
      check(!executed) { "Already Executed" }
      executed = true
    }
    transmitter.callStart()
    client.dispatcher.enqueue(AsyncCall(responseCallback))
  }
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.get().forWebSocket) {
        val existingCall = findExistingCallWithHost(call.host())
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
      }
    }
    promoteAndExecute()
  }

将任务加入到readyAsyncCalls等待执行的任务队列中

同步请求生成的是RealCal对象,异步请求生成的是AsyncCall

OkHttp 的处理网络异步请求的时候会有两个队列。一个是正在执行的队列,一个是等待执行的队列。

private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

关于ArrayDeque 任务队列请查看https://blog.youkuaiyun.com/m0_38089373/article/details/83933451

5、Dispatcher(调度器)

  5.1、Dispatcher是保存同步和异步Call的地方,并负责执行异步AsyncCall。

  5.2、根据以上源码分析,同步调用的时候使用了一个Deque(即runningSyncCalls队列)保存了ReaCall任务,在经过拦截器的处理之后,得到了响应的Response,最终会执行finally语句块:

   

 /** Used by `Call#execute` to signal completion.  */
  internal fun finished(call: RealCall) {
    finished(runningSyncCalls, call)
  }

  private fun <T> finished(calls: Deque<T>, call: T) {
    val idleCallback: Runnable?
    synchronized(this) {
      if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!") //将请求移除集合
      idleCallback = this.idleCallback
    }

    val isRunning = promoteAndExecute()

    if (!isRunning && idleCallback != null) {
      idleCallback.run()
    }
  }

对于同步请求,将请求移除集合,再调用promoteAndExecute方法

5.3 、对于异步调用,Dispatcher使用了两个Deque(一个readyAsyncCall,一个runningAsynCalls)  ,Dispatcher默认支持最大的并发请求是64个,单个Host最多执行5个并发请求,如果超过,则Call会先被放入到readyAsyncCall中,当出现空闲的线程时,再将readyAsyncCall中的线程移入到runningAsynCalls中,执行请求,其promoteAndExecute源码如下:

private fun promoteAndExecute(): Boolean {
    assert(!Thread.holdsLock(this))

    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.

        i.remove()
        asyncCall.callsPerHost().incrementAndGet()
        executableCalls.add(asyncCall)
        runningAsyncCalls.add(asyncCall)
      }
      isRunning = runningCallsCount() > 0
    }

    for (i in 0 until executableCalls.size) {
      val asyncCall = executableCalls[i]
      asyncCall.executeOn(executorService)
    }

    return isRunning
  }

@get:Synchronized var maxRequests = 64

@get:Synchronized var maxRequestsPerHost = 5
@Synchronized fun runningCallsCount(): Int = runningAsyncCalls.size + runningSyncCalls.size

先生成一个AsyncCall集合executableCalls,然后循环读取readyAsyncCall中任务队列,判断正在执行请求队列之和是否大于等于64,如果大于直接跳出循环,否则再判断单个Host正在执行的请求>=5,则进行重头下一个循环,否则将该请求任务从readyAsyncCalls队列移除,并将请求加入到executableCalls和runningAsyncCalls集合中,循环结束后, runningCallsCount为运行是同步任务和异步任务队列的大小的和,紧接着就是利用线程池执行该请求,返回判断runningCallsCount是否大于0

最后循环调用executeOn,

将线程加入到线程池中,进行多线程处理

fun executeOn(executorService: ExecutorService) {
      assert(!Thread.holdsLock(client.dispatcher))
      var success = false
      try {
        executorService.execute(this)
        success = true
      } catch (e: RejectedExecutionException) {
        val ioException = InterruptedIOException("executor rejected")
        ioException.initCause(e)
        transmitter.noMoreExchanges(ioException)
        responseCallback.onFailure(this@RealCall, ioException)
      } finally {
        if (!success) {
          client.dispatcher.finished(this) // This call is no longer running!
        }
      }
    }

execute(this)方法返回值为getResponseWithInterceptorChain()

 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()

@Throws(IOException::class)
  fun getResponseWithInterceptorChain(): Response {
    // Build a full stack of interceptors.
    val interceptors = mutableListOf<Interceptor>()
    //全局拦截器
    interceptors += client.interceptors
    //重定向、异步处理拦截器
    interceptors += RetryAndFollowUpInterceptor(client)
    //桥接拦截器,进行加入header头及gzip处理
    interceptors += BridgeInterceptor(client.cookieJar)
    //缓存拦截器
    interceptors += CacheInterceptor(client.cache)
    //连接拦截器
    interceptors += ConnectInterceptor
    //判断是否外部加入的网络拦截器
    if (!forWebSocket) {
      interceptors += client.networkInterceptors
    }
    //IO读写拦截器
    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 response = chain.proceed(originalRequest) 返回数据


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

@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
  }

7、如何执行任务呢?

通知调节器dispatcher我现在要开始执行任务了然后调用了getResponseInterceptorchain()方法

在这个方法执行结束以后会给我们返回一个通过http请求获取的response对象

最后会调用client.dispatcher.finish()来通知调度器dispatcher我现在任务执行结束了你可以让其他的任务来执行了

然后我们来说说它具体的执行过程,具体的执行过程是在getResponseInterceptorchain()中执行的

在这个方法里有一个泛型是interceptor也就是拦截器的集合在这个结合里存入了5个拦截器

之后创建了一个拦截链RealInterceptorChain();通过我们拦截链获取的对象去调用process()方法

这个也就是我们所说的链式调用

在这个方法中有一个索引值index每次我们去调用这个process方法的时候他都会加1

然后我们会根据这个索引值去判断我们去调用哪个拦截器当我们第一次调用这个方法的时候index为1会去调用我们集合当中

的第一个拦截器当拦截器执行完毕之后会去创建一个新的拦截链并且通过这个新的拦截链去再次调用process方法

然后去执行下一个拦截器

一直到所有的拦截器都调用完毕它会给我们返回一个的Request对象

而这个过程就是一个递归;

那么它是如何去判断我们已经调用到最后一个拦截器了那?

它是通过索引值index当index>集合的长度的时候那么它就会结束这个方法了因为我们index是从1开始的

所以需要index值大于集合长度的时候

我们集合里的拦截器才会全部执行完毕

  1. OKhttp的五大拦截器

一、RetryAndFollowUpInterceptor (重定向拦截器)

RetryAndFollowUpInterceptor 的拦截操作中做了这么几件事:

1、创建一个 StreamAllocation

2、发起请求

3、请求异常时会重试

4、根据响应码做重定向和重试

5、重定向时如果地址不一致会释放连接

6、另外也保存是否取消的状态值,在重试、请求得到响应后都会判断是否取消

二、BridgeInterceptor (桥接拦截器)

内置的拦截器中第二个是 BridgeInterceptor。Bridge,桥,什么桥?连接用户请求信息 和 HTTP 请求的桥梁。

BridgeInterceptor 负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应。

我们说下侨界拦截器大概都做了什么吧,请求前:>

1、如果这个请求有请求体,就添加 Content-Type, Content-Length 等>

2、如果这个请求没有 Host,就通过 url 来获取 Host 值添加到 Header 中>

3、如果这个请求没有接收的数据类型Accept-Encoding,且没指定接收的数据范围,就添加默认接受格式为 gzip>

5、去 CookieJar 中根据 url 查询 Cookie 添加到 Header>

6、如果当前没有,就添加 User-Agent 信息

发起请求后:

7、解析响应 Header 中的 Cookie

8、如果想要数据的格式是 gzip,就创建 GzipSource 进行解压,同时移除 Content-Encoding 和 Content-Length

三、CacheInterceptor (缓存拦截器)

第三个拦截器是缓存处理拦截器 CacheInterceptor,它的重要性用一句话来描述:最快的请求就是不请求,直接用缓存。

首先,根据request来判断cache中是否有缓存的response,如果有,得到这个response,然后进行判断当前response是否有效,

没有将cacheCandate赋值为空。

根据request判断缓存的策略,是否要使用了网络,缓存 或两者都使用

调用下一个拦截器,决定从网络上来得到response

如果本地已经存在cacheResponse,那么让它和网络得到的networkResponse做比较,决定是否来更新缓存的cacheResponse

缓存未经缓存过的response

四、ConnectInterceptor (连接拦截器)

我们知道,TCP 协议需要需要建立连接才能进行通信,每次请求都建立连接会极大地影响通信效率。

OkHttp 的优点之一优化了连接的建立:内部维护了可以重复使用的 Socket 连接池,减少握手次数,加快请求响应。

1、连接 RealConnection 是对 Socket 的封装

2、OkHttp 的连接复用主要是通过 StreamAllocation 来实现的,每个连接上持有一个。

3、StreamAllocation 引用的列表,以此来标识当前连接是否空闲

4、判断连接是否可以重用,除了比较连接当前的 host,也可以比较路由信息

5、连接池在添加新连接时会运行清理任务,默认最多空闲连接为 5,最长空闲时间为 5 分钟

五、CallServerInterceptor(读写拦截器)

最后一个拦截器,CallServerInterceptor,它负责实现网络 IO,所有拦截器都要依赖它才能拿到响应数据。

1、CallServerInterceptor 首先会将请求中的 header 写给服务器

2、如果有请求体的话,会再将 body 发送给服务器

3、最后通过httpCodec.finishRequest() 结束 http 请求的发送

4、然后从连接中读取服务器的响应,并构造 Response

5、如果请求的 header或服务器响应的 header 中,Connection 的值为 close,就关闭连接

6、最后返回 Response

Okhttp的精华就是维护了一个拦截器链,用户可传入的拦截器有两种:

一个是全局的拦截器interceptor,该类 interceptor 在整个拦截器链中最早被调用,通过 OkHttpClient.Builder#addInterceptor(Interceptor) 传入;
另外一个是非网页请求的 拦截器interceptor ,这类拦截器只会在非网页请求中被调用,并且是在组装完请求之后,真正发起网络请求前被调用,所有的 interceptor 被保存在 List<Interceptor> interceptors 集合中,按照添加顺序来逐个调用,具体可参考 RealCall#getResponseWithInterceptorChain() 方法。通过 OkHttpClient.Builder#addNetworkInterceptor(Interceptor) 传入;

https://blog.youkuaiyun.com/json_it/article/details/78404010

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值