OkHttp原理

1.网络请求中的核心原理:分发器,拦截器

分发器

作用:内部维护队列与线程池,完成请求调配

原理:当同时面对多个请求时,需要将其进行排队和分类,分为正在请求和等待请求

同步synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
}
同步请求不需要使用线性池,按顺序排队执行即可
异步synchronized void enqueue(AsyncCall call) {
    //请求数最大不超过64,同一Host请求不能超过5个
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost)       {
        runningAsyncCalls.add(call);
        executorService().execute(call);
    } else {
        readyAsyncCalls.add(call);
    }
}
异步请求正在请求任务不超过64,相同host请求不超过5,则会添加到正在请求,同时提交到线程池。否则加入等待请求中。调用分发器的finished方法,这里面会取出等待队列中的任务继续执行

拦截器

作用:完成请求过程

原理:

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
    )
    val response = chain.proceed(originalRequest)
  }

如上所示,构建了一个OkHttp拦截器的责任链。

责任链,顾名思义,就是用来处理相关事务责任的一条执行链,执行链上有多个节点,每个节点都有机会(条件匹配)处理请求事务,如果某个节点处理完了就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。

如上所示责任链添加的顺序及作用如下表所示:

拦截器作用
应用拦截器拿到的是原始请求,可以添加一些自定义header、通用参数、参数加密、网关接入等等。
RetryAndFollowUpInterceptor处理错误重试和重定向
BridgeInterceptor应用层和网络层的桥接拦截器,主要工作是为请求添加cookie、添加固定的header,比如Host、Content-Length、Content-Type、User-Agent等等,然后保存响应结果的cookie,如果响应使用gzip压缩过,则还需要进行解压。
CacheInterceptor缓存拦截器,如果命中缓存则不会发起网络请求。
ConnectInterceptor连接拦截器,内部会维护一个连接池,负责连接复用、创建连接(三次握手等等)、释放连接以及创建连接上的socket流。
networkInterceptors(网络拦截器)    用户自定义拦截器,通常用于监控网络层的数据传输。
CallServerInterceptor请求拦截器,在前置准备工作完成后,真正发起了网络请求。

我们的网络请求就是这样经过责任链一级一级的递推下去,最终会执行到CallServerInterceptor的intercept方法,此方法会将网络响应的结果封装成一个Response对象并return。之后沿着责任链一级一级的回溯,最终就回到getResponseWithInterceptorChain方法的返回。

2.OKHttp如何复用TCP连接?

ConnectInterceptor,连接拦截器,内部会维护一个连接池,负责连接复用、创建连接(三次握手等等)、释放连接以及创建连接上的socket流。

# ExchangeFinder
//为承载新的数据流 寻找 连接。寻找顺序是 已分配的连接、连接池、新建连接
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
    int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
  synchronized (connectionPool) {
    // 1.尝试使用 已给数据流分配的连接.(例如重定向请求时,可以复用上次请求的连接)
    releasedConnection = transmitter.connection;
    result = transmitter.connection;
 
    if (result == null) {
      // 2. 没有已分配的可用连接,就尝试从连接池获取。(连接池稍后详细讲解)
      if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {
        result = transmitter.connection;
      }
    }
  }
 
  synchronized (connectionPool) {
    if (newRouteSelection) {
      //3. 现在有了IP地址,再次尝试从连接池获取。可能会因为连接合并而匹配。(这里传入了routes,上面的传的null)
      routes = routeSelection.getAll();
      if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, false)) {
        foundPooledConnection = true;
        result = transmitter.connection;
      }
    }
 
  // 4.第二次没成功,就把新建的连接,进行TCP + TLS 握手,与服务端建立连接. 是阻塞操作
  result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
      connectionRetryEnabled, call, eventListener);
 
  synchronized (connectionPool) {
    // 5. 最后一次尝试从连接池获取,注意最后一个参数为true,即要求 多路复用(http2.0)
    //意思是,如果本次是http2.0,那么为了保证 多路复用性,(因为上面的握手操作不是线程安全)会再次确认连接池中此时是否已有同样连接
    if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, true)) {
      // 如果获取到,就关闭我们创建里的连接,返回获取的连接
      result = transmitter.connection;
    } else {
      //最后一次尝试也没有的话,就把刚刚新建的连接存入连接池
      connectionPool.put(result);
    }
  }
 
  return result;
}

3. OKHttp空闲连接如何清除?

原理:定时清楚

加入到链接池的连接开启计时,当连接数大于五或计时大于五分钟则移除空闲时间最长的连接,剩下的重新计时五分钟等待下一轮清除

4. OKHttp框架中用到了哪些设计模式?

  • 构建者模式:OkHttpClient与Request的构建都用到了构建者模式
  • 外观模式: OkHttp使用了外观模式,将整个系统的复杂性给隐藏起来,将子系统接口通过一个客户端OkHttpClient统一暴露出来。
  • 责任链模式: OKHttp的核心就是责任链模式,通过5个默认拦截器构成的责任链完成请求的配置
  • 享元模式: 享元模式的核心即池中复用,OKHttp复用TCP连接时用到了连接池,同时在异步请求中也用到了线程池

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OkHttp 是一个开源的 HTTP 客户端,用于 Android 平台和 Java 应用。它建立在 Java 的 HttpURLConnection 类之上,并提供了更简洁、更强大的 API。 OkHttp 的工作原理主要涉及以下几个关键组件: 1. `OkHttpClient`:这是 OkHttp 的核心类,负责配置和创建请求、设置拦截器、管理连接池等。你可以通过构建 OkHttpClient 实例来自定义请求的行为和参数。 2. `Request`:表示一个 HTTP 请求,包括 URL、请求方法(如 GET、POST)、请求体、请求头等信息。你可以通过 Request.Builder 构建一个 Request 实例。 3. `Response`:表示一个 HTTP 响应,包括响应码、响应体、响应头等信息。OkHttp 会将服务器返回的数据解析成 Response 对象。 4. `Interceptor`:拦截器用于在发送请求和接收响应之前进行一些额外的处理。OkHttp 提供了很多内置的拦截器,如重试拦截器、缓存拦截器等,同时也支持自定义拦截器。 5. `Dispatcher`:调度器负责管理请求的调度和执行。它可以控制同时并发执行的请求数量,还可以设置请求超时时间等。 6. `ConnectionPool`:连接池用于管理 HTTP 连接的复用和回收。OkHttp 会自动复用连接以减少网络延迟,提高性能。 7. `Cache`:缓存可以保存服务器返回的响应,以便在后续的请求中复用。OkHttp 支持对响应进行缓存,并提供了灵活的配置选项。 当你使用 OkHttp 发起一个网络请求时,它会通过 OkHttpClient 来创建一个 Request 对象,并通过 Dispatcher 来执行这个请求。在执行过程中,OkHttp 会根据设置的拦截器进行一系列的处理,如添加请求头、重试、缓存等。最终,OkHttp 将返回一个 Response 对象,你可以从中获取到服务器返回的数据。 总体来说,OkHttp 的工作原理是通过封装底层的 HttpURLConnection,提供了简洁易用的 API,并通过拦截器和连接池等机制优化了网络请求的性能和可定制性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值