OkHttp源码解析笔记

OkHttp源码解析笔记

本篇OkHttp源码基于3.0 Kotlin版本

1.Retrofit的基本使用

首先看OkHttp的基本使用

fun main(){
   val okHttpClient = OkHttpClient().newBuilder().build()
   val request = Request.Builder()
            .method("", null)
            .url("")
            .build()
   val call = okHttpClient.newCall(request)
    //同步
   call.execute()
    //异步
   call.enqueue(object: Callback{
                override fun onFailure(call: Call, e: IOException) {}
                override fun onResponse(call: Call, response: Response) {}
            }
    )
}

2.从OkHttp的基本API入手:

从OkHttpClient类的newCall函数出发,看下面代码注释

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

		override fun newCall(request: Request): Call {

    	//RealCall是OkHttp的核心类,
		//分别从RealCall类的enqueue和execute入手看源码
    	return RealCall.newRealCall(this, request, forWebSocket = false)

  		}
}

接着看RealCall类的同步请求函数,将同步请求交给任务调度类Dispatcher

internal class RealCall private constructor(
  	val client: OkHttpClient,val originalRequest: Request,
  	val forWebSocket: Boolean
	) : Call {
		
		override fun execute(): Response {
		    synchronized(this) {
		      check(!executed) { "Already Executed" }
		      executed = true
		    }
		    transmitter.timeoutEnter()
		    transmitter.callStart()
		    try {

			  //将同步请求交给任务调度类 Dispatcher
		      client.dispatcher.executed(this) 
			  //核心在这个getResponseWithInterceptorChain函数
		      return getResponseWithInterceptorChain()

		    } finally {
		      client.dispatcher.finished(this)
		    }
  		}

}
class Dispatcher constructor() {

	@Synchronized internal fun executed(call: RealCall) {
		    //添加到同步运行队列中
		    runningSyncCalls.add(call)
  	}
}

可以看到同步请求走到getResponseWithInterceptorChain函数,这里我们先卡住,先看异步请求

internal class RealCall private constructor(
  	val client: OkHttpClient,val originalRequest: Request,
  	val forWebSocket: Boolean
	) : Call {

		  //http异步执行请求的调用从这里开始
		  override fun enqueue(responseCallback: Callback) {
		    //是否已执行
		    synchronized(this) {
		      check(!executed) { "Already Executed" }
		      executed = true
		    }
		    transmitter.callStart()
		    // 将异步任务 交给 Dispatcher(调度器) 去执行
		    client.dispatcher.enqueue(AsyncCall(responseCallback))
		  }

}

可以看到异步请求同样交给任务调度器Dispatcher,接着看Dispatcher类的enqueue函数

class Dispatcher constructor() {

		//okHttp调用的enqueue进行异步请求
		  //实际是调用到这里的Dispatcher(调度器)类的enqueue函数
		internal fun enqueue(call: AsyncCall) {
		    synchronized(this) {
		      //添加到异步等待队列
		      readyAsyncCalls.add(call)
		
		      //这里的forWebSocket变量已经在OkHttpClient的newCall函数中给赋予 false
		      if (!call.get().forWebSocket) {
		        val existingCall = findExistingCallWithHost(call.host())
		          // 使call共享已存在的同一主机
		        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
		      }
		    }
		    promoteAndExecute() //重点从这里开始
}

enqueue函数的核心在调用了promoteAndExecute函数,promoteAndExecute函数内的主要工作:

  • 1.遍历等待队列,满足 “运行队列的个数不超过64个,同一个host不超过5条线程执行请求” 的条件下,将等待线程添加到到运行队列中,并且执行该线程
  • 2.当前还有运行请求中的线程 则返回true, 否则返回false
private fun promoteAndExecute(): Boolean {
		    this.assertThreadDoesntHoldLock()
		
		    val executableCalls = mutableListOf<AsyncCall>()
		    val isRunning: Boolean
		    synchronized(this) {
		      val i = readyAsyncCalls.iterator()  //readyAsyncCalls: 异步等待线程队列

		      //对异步等待队列进行迭代
		      while (i.hasNext()) {
		        val asyncCall = i.next()
		        //能进行的最大请求数不能超过  maxRequests = 64 个
		        if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
		        // 同一个host最多允许maxRequestsPerHost = 5条线程通知执行请求
		        if (asyncCall.callsPerHost().get() >= this.maxRequestsPerHost) continue // Host max capacity.
		
		        i.remove()
		        asyncCall.callsPerHost().incrementAndGet() //同一个host +1 
		        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
		  }

}

接着看asyncCall.executeOn(executorService)这句代码,这句代码是执行 添加到运行队列的线程,可以看到此处的AsyncCall是RealCall类的内部类,AyncCall继承自Runnable

internal class RealCall private constructor(
	  val client: OkHttpClient,  val originalRequest: Request,
	  val forWebSocket: Boolean
	) : Call {

		internal inner class AsyncCall(
		    private val responseCallback: Callback
		  ) : Runnable {
			
			fun executeOn(executorService: ExecutorService) {
	
		      client.dispatcher.assertThreadDoesntHoldLock()
		
		      var success = false
		      try {
		        //线程池里执行线程,执行下面的run函数
		        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!
		        }
		      }
		    }
		    //核心在run函数的getResponseWithInterceptorChain方法
		    override fun run() {
		      threadName("OkHttp ${redactedUrl()}") {
		        var signalledCallback = false
		        transmitter.timeoutEnter()
		        try {
		          //这里的getResponseWithInterceptorChain函数是OkHttp的核心,
				  //同步、异步请求都会调用getResponseWithInterceptorChain这个函数
		          val response = getResponseWithInterceptorChain()
		          signalledCallback = true
		          responseCallback.onResponse(this@RealCall, response)
		        } catch (e: IOException) {
		          if (signalledCallback) {
		            // Do not signal the callback twice!
		            Platform.get().log("Callback failure for ${toLoggableString()}", INFO, e)
		          } else {
		            responseCallback.onFailure(this@RealCall, e)
		          }
		        } catch (t: Throwable) {
		          cancel()
		          if (!signalledCallback) {
		            val canceledException = IOException("canceled due to $t")
		            canceledException.addSuppressed(t)
		            responseCallback.onFailure(this@RealCall, canceledException)
		          }
		          throw t
		        } finally {
		          client.dispatcher.finished(this)
		        }
		      }
		    }
	
		}
}

在这里,异步请求跟同步请求一样执行到getResponseWithInterceptorChain这个函数,接着我们先看下上面代码处的两处finally,都调用到finished

class Dispatcher constructor() {

		internal fun finished(call: AsyncCall) {
			//将运行的地址host集合 减 1
		    call.callsPerHost().decrementAndGet()  
		    finished(runningAsyncCalls, 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
		    }

		    //这里之所以执行promoteAndExecute函数,是要检查等待队列是否存在等待线程,如果存在,遍历等待队列的线程并
		    //检验执行队列的线程数是否达到最大数(64),如果没有达到最大数,则将等待线程加入到请求队列中,这样也就确保了等待队列能够
		    //及时添加到执行队列,确保了等待队列的线程能被执行
		    val isRunning = promoteAndExecute()
		
		    if (!isRunning && idleCallback != null) {//没有运行的线程
		      idleCallback.run()//启动之前闲置的线程
		    }
		 }
}

可以看到Dispatcher类的finished函数主要做了两件事:

  • 移除 无响应线程或执行完成的线程
  • 调用上面提到的promoteAndExecute函数,对等待队列和运行队列进行调度,使得等待线程可以及时被执行

接着回到getResponseWithInterceptorChain这个函数,可以看到主要配置了多个拦截器,而这些拦截器负责对请求数据和响应数据进行处理,内部采用的是责任链模式, 然后创建RealInterceptorChain这个责任链的调度类,调用其proceed函数开启责任链

@Throws(IOException::class)
fun getResponseWithInterceptorChain(): Response {
	    // Build a full stack of interceptors.
	    //TODO 责任链
	    val interceptors = mutableListOf<Interceptor>()
	    //TODO 在配置okhttpClient 时设置的intercept 由用户自己设置
	    interceptors += client.interceptors
	    //TODO 负责处理失败后的重试与重定向
	    interceptors += RetryAndFollowUpInterceptor(client)
	    //TODO 深加工用户传递来的请求,设置默认请求头;用户没有设置时默认采用 gzip 压缩解压数据
	    interceptors += BridgeInterceptor(client.cookieJar)
	    //TODO 处理 缓存配置 根据条件(存在响应缓存并被设置为不变的或者响应在有效期内)返回缓存响应
	    //TODO 设置请求头(If-None-Match、If-Modified-Since等) 服务器可能返回304(未修改)
	    //TODO 可配置用户自己设置的缓存拦截器
	    interceptors += CacheInterceptor(client.cache)
	    //TODO 连接服务器,负责和服务器建立连接
	    interceptors += ConnectInterceptor
	    if (!forWebSocket) {
	      //TODO 配置OkhttpClient 时设置的networkInterceptors
	      //TODO 返回观察单个网络请求和响应的不可变拦截器列表。
	      interceptors += client.networkInterceptors
	    }
	    //TODO 执行流操作(写出请求体、获得响应数据) 负责向服务器发送请求数据、从服务器读取响应数据
	    //TODO 进行http请求报文的封装与请求报文的解析
	    interceptors += CallServerInterceptor(forWebSocket)
	    //TODO 创建责任链
	    val chain = RealInterceptorChain(interceptors, transmitter, null, 0, originalRequest, this,
	        client.connectTimeoutMillis, client.readTimeoutMillis, client.writeTimeoutMillis)
	
	    var calledNoMoreExchanges = false
	    try {
	      //TODO 执行责任链
	      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)
	      }
	    }
}

下面看下CacheInterceptor缓存拦截器部分的实现, 可以看到:

  • 缓存拦截器会根据请求的信息和缓存的响应的信息来判断是否存在缓存可用;
  • 如果有可以使用的缓存,那么就返回该缓存给用户,否则就继续使用责任链模式来从服务器中获取响应;
  • 当获取到响应的时候,又会把响应缓存到磁盘上面,最后返回reseponse
class CacheInterceptor(internal val cache: Cache?): Interceptor {

		  @Throws(IOException::class)
		  override fun intercept(chain: Interceptor.Chain): Response {
		    //根据request得到cache中缓存的response,
		    // 如果用户没有配置缓存拦截器:  cacheCandidate == null,则说明cache(用户自配的缓存拦截器)也是为null
		    val cacheCandidate = cache?.get(chain.request())
		
		    val now = System.currentTimeMillis()
		    // request判断缓存策略,是否使用了网络、缓存或两者都使用
		    val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()
		    //如果networkRequest == null 则说明不使用网络请求
		    val networkRequest = strategy.networkRequest
		    //获取缓存中(CacheStrategy)的Response
		    val cacheResponse = strategy.cacheResponse
		
		    cache?.trackResponse(strategy)
		
		    //缓存无效 关闭资源
		    if (cacheCandidate != null && cacheResponse == null) {
		      // The cache candidate wasn't applicable. Close it.
		      cacheCandidate.body?.closeQuietly()
		    }
		
		    // If we're forbidden from using the network and the cache is insufficient, fail.
		    //networkRequest == null 不使用网路请求 且没有缓存 cacheResponse == null  返回失败
		    if (networkRequest == null && cacheResponse == null) {
		      return Response.Builder()
		          .request(chain.request())
		          .protocol(Protocol.HTTP_1_1)
		          .code(HTTP_GATEWAY_TIMEOUT)
		          .message("Unsatisfiable Request (only-if-cached)")
		          .body(EMPTY_RESPONSE)
		          .sentRequestAtMillis(-1L)
		          .receivedResponseAtMillis(System.currentTimeMillis())
		          .build()
		    }
		
		    // If we don't need the network, we're done.
		    //不使用网络请求 且存在缓存 直接返回响应
		    if (networkRequest == null) {
		      return cacheResponse!!.newBuilder()
		          .cacheResponse(stripBody(cacheResponse))
		          .build()
		    }
		
		    var networkResponse: Response? = null
		    try {
		      //调用下一个拦截器,从网络上获取数据
		      networkResponse = chain.proceed(networkRequest)
		    } finally {
		      // If we're crashing on I/O or otherwise, don't leak the cache body.
		      if (networkResponse == null && cacheCandidate != null) {
		        cacheCandidate.body?.closeQuietly()
		      }
		    }
		
		    // If we have a cache response too, then we're doing a conditional get.
		    // 如果本地已经存在cacheResponse,那么让它和网络得到的networkResponse做比较,决定是否来更新缓存的cacheResponse
		    if (cacheResponse != null) {
		      //HTTP_NOT_MODIFIED = 304 : 告知客户端,服务端内容未改变,不会返回数据,继续使用上一次的响应的内容
		      if (networkResponse?.code == HTTP_NOT_MODIFIED) {
		        val response = cacheResponse.newBuilder()
		            .headers(combine(cacheResponse.headers, networkResponse.headers))
		            .sentRequestAtMillis(networkResponse.sentRequestAtMillis)
		            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis)
		            .cacheResponse(stripBody(cacheResponse))
		            .networkResponse(stripBody(networkResponse))
		            .build()
		
		        networkResponse.body!!.close()
		
		        // Update the cache after combining headers but before stripping the
		        // Content-Encoding header (as performed by initContentStream()).
		        cache!!.trackConditionalCacheHit()
		        cache.update(cacheResponse, response)  //更新DiskLruCache缓存
		        return response
		      } else {
		        cacheResponse.body?.closeQuietly()
		      }
		    }
		
		    val response = networkResponse!!.newBuilder()
		        .cacheResponse(stripBody(cacheResponse))
		        .networkResponse(stripBody(networkResponse))
		        .build()
		    //cache不为null,说明用户自己配置了缓存拦截器
		    if (cache != null) {
		      // 缓存未经缓存过的response
		      if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) {
		        // Offer this request to the cache.
		        val cacheRequest = cache.put(response)
		        return cacheWritingResponse(cacheRequest, response)
		      }
		
		      if (HttpMethod.invalidatesCache(networkRequest.method)) {
		        try {
		          cache.remove(networkRequest)
		        } catch (_: IOException) {
		          // The cache cannot be written.
		        }
		      }
		    }
		
		    return response
		  }
}

接着看ConnectInterceptor连接拦截器的实现,可以看到

  • 1.判断当前的连接是否可以使用:流是否已经被关闭,并且已经被限制创建新的流;
  • 2.如果当前的连接无法使用,就从连接池中获取一个连接;
  • 3.连接池中也没有发现可用的连接,创建一个新的连接,并进行握手,然后将其放到连接池中。
  • 补充:连接复用的一个好处就是省去了进行 TCP 和 TLS 握手的一个过程。因为建立连接本身也是需要消耗一些时间的,连接被复用之后可以提升我们网络访问的效率
class ExchangeFinder(
	  private val transmitter: Transmitter,
	  private val connectionPool: RealConnectionPool,
	  private val address: Address,
	  private val call: Call,
	  private val eventListener: EventListener
	) {

		  @Throws(IOException::class)
		  private fun findConnection(
		    connectTimeout: Int,
		    readTimeout: Int,
		    writeTimeout: Int,
		    pingIntervalMillis: Int,
		    connectionRetryEnabled: Boolean
		  ): RealConnection {

		    var foundPooledConnection = false
		    var result: RealConnection? = null
		    var selectedRoute: Route? = null
		    var releasedConnection: RealConnection?
		    val toClose: Socket?
		    synchronized(connectionPool) {
		      if (transmitter.isCanceled) throw IOException("Canceled")
		      hasStreamFailure = false // This is a fresh attempt.
		      // 尝试使用已分配的连接,已经分配的连接可能已经被限制创建新的流
		      releasedConnection = transmitter.connection
		      // 释放当前连接的资源,如果该连接已经被限制创建新的流,就返回一个Socket以关闭连接
		      toClose = if (transmitter.connection != null && transmitter.connection!!.noNewExchanges) {
		        transmitter.releaseConnectionNoEvents()
		      } else {
		        null
		      }
		
		      if (transmitter.connection != null) {
		        // We had an already-allocated connection and it's good.
		        result = transmitter.connection
		        releasedConnection = null
		      }
		
		      if (result == null) {
		        // Attempt to get a connection from the pool.
		        //尝试从连接池中获取一个连接
		        if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {
		          foundPooledConnection = true
		          result = transmitter.connection
		        } else if (nextRouteToTry != null) {
		          selectedRoute = nextRouteToTry
		          nextRouteToTry = null
		        } else if (retryCurrentRoute()) {
		          selectedRoute = transmitter.connection!!.route()
		        }
		      }
		    }
		    //关闭连接
		    toClose?.closeQuietly()
		
		    if (releasedConnection != null) {
		      eventListener.connectionReleased(call, releasedConnection!!)
		    }
		    if (foundPooledConnection) {
		      eventListener.connectionAcquired(call, result!!)
		    }
		    if (result != null) {
		      // If we found an already-allocated or pooled connection, we're done.
		      // 如果已经从连接池中获取到了一个连接,就将其返回
		      return result!!
		    }
		
		    // If we need a route selection, make one. This is a blocking operation.
		    var newRouteSelection = false
		    if (selectedRoute == null && (routeSelection == null || !routeSelection!!.hasNext())) {
		      newRouteSelection = true
		      routeSelection = routeSelector.next()
		    }
		
		    var routes: List<Route>? = null
		    synchronized(connectionPool) {
		      if (transmitter.isCanceled) throw IOException("Canceled")
		
		      if (newRouteSelection) {
		        // Now that we have a set of IP addresses, make another attempt at getting a connection from
		        // the pool. This could match due to connection coalescing.
		        // 根据一系列的 IP地址从连接池中获取一个链接
		        routes = routeSelection!!.routes
		        if (connectionPool.transmitterAcquirePooledConnection(
		                address, transmitter, routes, false)) {
		          foundPooledConnection = true
		          result = transmitter.connection
		        }
		      }
		
		      if (!foundPooledConnection) {
		        if (selectedRoute == null) {
		          selectedRoute = routeSelection!!.next()
		        }
		
		        // Create a connection and assign it to this allocation immediately. This makes it possible
		        // for an asynchronous cancel() to interrupt the handshake we're about to do.
		        //在连接池中如果没有该连接,则创建连接并立即将其分配。这使得异步cancel()可以中断我们即将进行的握手
		        result = RealConnection(connectionPool, selectedRoute!!)
		        connectingConnection = result
		      }
		    }
		
		    // If we found a pooled connection on the 2nd time around, we're done.
		    if (foundPooledConnection) {
		      // 如果我们在第二次 (第一次在上面的代码) 的时候发现了一个连接池的连接,那么我们就将其返回
		      eventListener.connectionAcquired(call, result!!)
		      return result!!
		    }
		
		    // Do TCP + TLS handshakes. This is a blocking operation.
		    // 进行 TCP 和 TLS 握手
		    result!!.connect(
		        connectTimeout,
		        readTimeout,
		        writeTimeout,
		        pingIntervalMillis,
		        connectionRetryEnabled,
		        call,
		        eventListener
		    )
		    connectionPool.routeDatabase.connected(result!!.route())
		
		    var socket: Socket? = null
		    synchronized(connectionPool) {
		      connectingConnection = null
		      // Last attempt at connection coalescing, which only occurs if we attempted multiple
		      // concurrent connections to the same host.
		      if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, true)) {
		        // We lost the race! Close the connection we created and return the pooled connection.
		        result!!.noNewExchanges = true
		        socket = result!!.socket()
		        result = transmitter.connection
		
		        // It's possible for us to obtain a coalesced connection that is immediately unhealthy. In
		        // that case we will retry the route we just successfully connected with.
		        nextRouteToTry = selectedRoute
		      } else {
		        connectionPool.put(result!!)
		        transmitter.acquireConnectionNoEvents(result!!)
		      }
		    }
		    socket?.closeQuietly()
		
		    eventListener.connectionAcquired(call, result!!)
		    return result!!
		  
}

再看下ConnectInterceptor连接拦截器的连接线程池是怎么管理连接的

class RealConnectionPool(
	  taskRunner: TaskRunner,
	  private val maxIdleConnections: Int,
	  keepAliveDuration: Long,
	  timeUnit: TimeUnit
	) {

		   private val cleanupQueue: TaskQueue = taskRunner.newQueue()
		   //2.连接队列
		   private val cleanupTask = object : Task("OkHttp ConnectionPool") {
		     override fun runOnce() = cleanup(System.nanoTime())
		  }

		  //1. 往连接队列中添加连接,并定时管理连接队列
		  fun put(connection: RealConnection) {
		    this.assertThreadHoldsLock()
		    //往连接队列中添加连接
		    connections.add(connection)
		    //并定时管理连接队列
		    cleanupQueue.schedule(cleanupTask)
		  }

		  3. 管理连接队列
		  fun cleanup(now: Long): Long {

		    var inUseConnectionCount = 0
		    var idleConnectionCount = 0
		    var longestIdleConnection: RealConnection? = null
		    var longestIdleDurationNs = Long.MIN_VALUE
		
		    // Find either a connection to evict, or the time that the next eviction is due.
		    synchronized(this) {
		      //遍历队列中的连接
		      for (connection in connections) {
		        // If the connection is in use, keep searching.
		        if (pruneAndGetAllocationCount(connection, now) > 0) {
		          inUseConnectionCount++
		          continue
		        }
		
		        idleConnectionCount++
		
		        // If the connection is ready to be evicted, we're done.
		        //找到 可以被清理 + 闲置时间最长的连接
		        val idleDurationNs = now - connection.idleAtNanos
		        if (idleDurationNs > longestIdleDurationNs) {
		          longestIdleDurationNs = idleDurationNs
		          longestIdleConnection = connection
		        }
		      }
		
		      when {
		        // maxIdleConnections 表示最大允许的闲置的连接的数量,
		        // keepAliveDurationNs表示连接允许存活的最长的时间
		        // 默认空闲连接最大数目为5个,keepalive 时间最长为5分钟
		        longestIdleDurationNs >= this.keepAliveDurationNs
		            || idleConnectionCount > this.maxIdleConnections -> {
		          // We've found a connection to evict. Remove it from the list, then close it below
		          // (outside of the synchronized block).
		          // 该连接的时长超出了最大的活跃时长或者闲置的连接数量超出了最大允许的范围,直接移除
		          connections.remove(longestIdleConnection)
		          if (connections.isEmpty()) cleanupQueue.cancelAll()
		        }
		        idleConnectionCount > 0 -> {
		          // A connection will be ready to evict soon.
		          // 闲置的连接的数量大于0,返回 等待下次清理的时间
		          return keepAliveDurationNs - longestIdleDurationNs
		        }
		        inUseConnectionCount > 0 -> {
		          // All connections are in use. It'll be at least the keep alive duration 'til we run
		          // again.
		          // 所有的连接都在使用中,5分钟后再进行下一次清理
		          return keepAliveDurationNs
		        }
		        else -> {
		          // No connections, idle or in use.
		          // 没有连接
		          return -1
		        }
		      }
		    }
		
		    longestIdleConnection!!.socket().closeQuietly()
		
		    // Cleanup again immediately.
		    return 0L
		  }

}

可以从上面看到:

  • 首先会对缓存中的连接进行遍历,以寻找一个闲置时间最长的可被清理的连接;

  • 然后根据该连接的闲置时长和最大允许的连接数量等参数来决定是否应该清理该连接,同时注意上面的方法的返回值是一个时间;

    • 如果该连接的时长超出了最大的活跃时长或者闲置的连接数量超出了最大允许的范围,直接移除
    • 如果闲置时间最长的连接仍然需要一段时间才能被清理的时候,会返回这段时间的时间差,然后会在这段时间之后再次对连接池进行清理
    • 如果所有的连接都在使用中,5分钟后再进行下一次清理
    • 不存在连接,则返回-1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值