okhttp原理

发布于:2025-05-12 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、核心架构与设计模式

  1. 拦截器链(Interceptor Chain)
    • 责任链模式:通过 RealInterceptorChain 按顺序执行拦截器,每个拦截器可修改请求/响应

• 五大核心拦截器(按执行顺序):

  1. RetryAndFollowUpInterceptor:处理重定向和失败重试
    ◦ 自动重试机制:通过 StreamAllocation 寻找新的路由(Route)和连接(Connection)

    ◦ 最多重试次数:20次(源码常量 MAX_FOLLOW_UPS

  2. BridgeInterceptor:补全请求头(User-Agent, Cookie等)
    ◦ 自动添加 Content-TypeContent-Length 等必要头信息

  3. CacheInterceptor:缓存管理(基于HTTP缓存协议)
    ◦ 使用 CacheStrategy 判断是否使用缓存(根据 Cache-Control 头)

  4. ConnectInterceptor:建立网络连接
    ◦ 关键类 RealConnection:封装TCP/TLS连接,复用连接的关键

  5. CallServerInterceptor:发送请求并读取响应
    ◦ 通过 HttpCodec 处理HTTP协议编解码

  6. 连接池(ConnectionPool)
    • 复用机制:通过 ConnectionPool 管理空闲连接(默认最大空闲连接数5,存活时间5分钟)

public ConnectionPool(int maxIdleConnections, long keepAliveDuration) {
  this.maxIdleConnections = maxIdleConnections; // 默认5
  this.keepAliveDurationNs = keepAliveDuration; // 默认5分钟
}

• 连接复用条件:相同Host + 相同SocketFactory + 相同代理配置

• LRU清理策略:后台线程定期清理过期/空闲连接


二、异步请求与线程管理
高频考点:Dispatcher 工作机制、线程池配置

  1. Dispatcher 调度器
    • 异步请求队列:维护两个队列

         • runningAsyncCalls:正在执行的异步请求(默认最大64)

        • readyAsyncCalls:等待执行的异步请求

        • executorService:线程池(核心线程数0,最大线程数Integer.MAX_VALUE)

        • 最大并发请求数:默认同一域名最大5个并发(通过 Dispatcher.setMaxRequestsPerHost 设置)

        线程池优化

        • CachedThreadPool:避免频繁创建/销毁线程

    public synchronized ExecutorService executorService() {
      if (executorService == null) {
        executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
            new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
      }
      return executorService;
    }

            2.同步请求队列 runningSyncCalls   


    三、关键源码解析
    高频考点:同步/异步请求流程、连接复用实现

    1. 请求执行流程
      • 同步请求:
    // OkHttpClient.newCall(request).execute()
    public Response execute() {
      synchronized (this) {
        // 检查是否已执行
        executed = true;
      }
      transmitter.timeoutEnter(); // 超时管理
      transmitter.prepareToConnect(request);
      // 加入运行队列
      client.dispatcher().executed(this);
      // 执行拦截器链
      return getResponseWithInterceptorChain();
    }

    • 异步请求:

    enqueue实际上是new了一个RealCall的内部类AsyncCall扔进了dispatcher中,如果当前正在运行的异步请求数小于阈值maxRequests (默认Dispatcher中为64)并且同host下运行的请求小于阈值maxRequestsPerHost(默认Dispatcher中为5),就将AsyncCall添加到正在运行的异步队里,并通过线程池异步执行,否则就将其丢到等待队列排队。

      // OkHttpClient.newCall(request).enqueue(callback)
      void enqueue(AsyncCall call) {
        synchronized (this) {
          readyAsyncCalls.add(call);
        }
        promoteAndExecute(); // 调度执行
      }
      1. 连接复用实现
        • RealConnection 复用逻辑:
      // StreamAllocation.findConnection()
      if (connection != null) {
        releasedConnection = this.connection;
        result = releasedConnection;
        releasedConnection = null;
        if (!result.isEligible(address.url().host(), address.url().host())) {
          result = null;
        }
      }

      四、高频面试题与答案

      1. OkHttp如何实现连接复用?
        • 通过ConnectionPool管理空闲连接,复用相同Host+Port的连接

        • 使用Connection: keep-alive头实现HTTP/1.1长连接

      2. 拦截器执行顺序是怎样的?
        • RetryAndFollowUp → Bridge → Cache → Connect → CallServer

      3. 如何优化大文件下载?
        • 使用OkHttpClient配置连接/读取超时

        • 通过拦截器实现分块下载(Range头)

      4. 如何处理SSL/TLS握手?
        • 使用SSLSocketFactoryHostnameVerifier

        • 证书锁定(Certificate Pinning)示例:

        CertificatePinner pinner = new CertificatePinner.Builder()
            .add("publicobject.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAA=")
            .build();
      5. 使用到的设计模式

              • 策略模式(在CacheInterceptor中,在响应数据的选择中使用了策略模式,选择缓存数据还是选择网络访问。)

              • 责任链模式(拦截器的链式调用)


      五、总结
      OkHttp面试题核心要点:

      1. 拦截器链责任链模式的执行顺序与作用
      2. 连接池管理策略(LRU、最大空闲数)
      3. Dispatcher异步调度机制与线程池配置
      4. 缓存策略(Cache-Control与磁盘缓存)

      网站公告

      今日签到

      点亮在社区的每一天
      去签到