OkHttp源码流程简述

1、OkHttp请求整体流程是怎样的

  • 构建OkhttpClient对象
  • 构建Request对象
  • Request传入到newCall方法生成Realcall对象,用它来发起新请求
  • 分发器维护请求队列和线程池,完成请求调配
    • 同步-》realcall中的execute方法,client.dispatcher().executed(this);执行runningSyncCalls.add(call); 再执行getResponseWithInterceptorChain
    • 异步-》realcall中的enqueue方法,client.dispatcher().enqueue(new AsyncCall(responseCallback));分发器中加到异步请求队列。再线程池请求,最终调用到getResponseWithInterceptorChain
  • 执行getResponseWithInterceptorChain跑到拦截器
  • 执行chain.proceed(originalRequest)返回结果Response

2、分发器是如何工作的?

2.1 同步

  • Realcall.execute() 会跑到分发器Dispatcher.java 执行execute()

  • 加到runningSyncCalls也就是同步线程队列中

  • 调用getResponseWithInterceptorChain()运行拦截器用的责任链模式,最终返回Response

  • 用完移除RealCall 调用client.dispatcher().finished(this);

java 复制代码
-------------Realcall.java

@Override public Response execute() throws IOException {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  transmitter.timeoutEnter();
  transmitter.callStart();
  try {
  //1、 分发器执行execute 传入
    client.dispatcher().executed(this);
  // 2、执行getResponseWithInterceptorChain()
    return getResponseWithInterceptorChain();
  } finally {
  //3、用完移除RealCall
    client.dispatcher().finished(this);
  }
}
JAVA 复制代码
-------------Dispatcher.java
synchronized void executed(RealCall call) {
  runningSyncCalls.add(call);
}

2.2 异步

2.2.1 异步执行流程

  • Realcall.enqueue(new AsyncCall())
  • 请求数不超过64,且同一host请求不能超过5个。
    • 加入到runningAsyncCalls
    • 加入到线程池中中执行,executorService().execute(call);
    • 每个任务完成后,都会调用分发器的finished方法,这里面会取出等待队列readyAsyncCalls中的任务继续执行
  • 否则加入到等待队列readyAsyncCalls中
java 复制代码
-------------Dispatcher.java
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);
    }
}

2.2.2 异步AysncCall类分析

  • AysncCall继承了抽象类NamedRunnable,线程池最终会跑AysncCall的run方法,执行到了AysncCall的execute方法,跑到getResponseWithInterceptorChain()
java 复制代码
final class AsyncCall extends NamedRunnable {
  private final Callback responseCallback;
  private volatile AtomicInteger callsPerHost = new AtomicInteger(0);

  AsyncCall(Callback responseCallback) {
    super("OkHttp %s", redactedUrl());
    this.responseCallback = responseCallback;
  }
 ...

  @Override protected void execute() {
    boolean signalledCallback = false;
    transmitter.timeoutEnter();
    try {
      Response response = getResponseWithInterceptorChain();
      signalledCallback = true;
      responseCallback.onResponse(RealCall.this, response);
    } catch (IOException e) {
      if (signalledCallback) {
        // Do not signal the callback twice!
        Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
      } else {
        responseCallback.onFailure(RealCall.this, e);
      }
    } catch (Throwable t) {
      cancel();
      if (!signalledCallback) {
        IOException canceledException = new IOException("canceled due to " + t);
        canceledException.addSuppressed(t);
        responseCallback.onFailure(RealCall.this, canceledException);
      }
      throw t;
    } finally {
      client.dispatcher().finished(this);
    }
  }
}

JAVA 复制代码
public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

3、拦截器如何工作?

  • 责任链设计是 将请求者执行者进行解耦,请求发了,不用关心细节。这个链上的每一个节点都有机会处理请求,处理完了交给下一个,呈一个U形结构。如下图所示。CallServerInterceptorintercept方法,此方法会将网络响应的结果封装成一个Response对象并return

    • 应用拦截器(用户可自定义)
      • 拿到最原始请求,可以添加自定义header、通用参数等
    • 重试重定向拦截器
      • 处理错误重试和重定向
    • 桥接拦截器
      • 应用层和网络层的桥接拦截器,主要工作是条件cookie、固定和header,保存结果的cookie,如响应用过gzip压缩过,就还需要解压
    • 缓存拦截器
      • 如果命中缓存则不会发起网络请求
    • 连接拦截器
      • 内部维护一个连接池,负责连接服用、创建连接(3次握手)、释放连接以及创建连接上的socket流
    • 网络拦截器(用户可自定义)
      • 通常用于检测网络层的数据连接
    • 请求服务拦截器
      • 前置准备工作完成后,真正发起网络请求
java 复制代码
Response getResponseWithInterceptorChain() throws IOException {
  // Build a full stack of interceptors.
  List<Interceptor> interceptors = new ArrayList<>();
  interceptors.addAll(client.interceptors());
  interceptors.add(new RetryAndFollowUpInterceptor(client));
  interceptors.add(new BridgeInterceptor(client.cookieJar()));
  interceptors.add(new CacheInterceptor(client.internalCache()));
  interceptors.add(new ConnectInterceptor(client));
  if (!forWebSocket) {
    interceptors.addAll(client.networkInterceptors());
  }
  interceptors.add(new CallServerInterceptor(forWebSocket));

  Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
      originalRequest, this, client.connectTimeoutMillis(),
      client.readTimeoutMillis(), client.writeTimeoutMillis());

  boolean calledNoMoreExchanges = false;
  try {
    Response response = chain.proceed(originalRequest);
    if (transmitter.isCanceled()) {
      closeQuietly(response);
      throw new IOException("Canceled");
    }
    return response;
  } catch (IOException e) {
    calledNoMoreExchanges = true;
    throw transmitter.noMoreExchanges(e);
  } finally {
    if (!calledNoMoreExchanges) {
      transmitter.noMoreExchanges(null);
    }
  }
}
相关推荐
DO_Community2 小时前
普通服务器都能跑:深入了解 Qwen3-Next-80B-A3B-Instruct
人工智能·开源·llm·大语言模型·qwen
代码s贝多芬的音符3 小时前
ios android 小程序 蓝牙 CRC16_MODBUS
android·ios·小程序
mortimer3 小时前
零依赖、高效率的语音转文字c++版 whisper.cpp (附批量处理脚本)
开源·github
2501_915918415 小时前
iOS 混淆实战 多工具组合完成 IPA 混淆、加固与工程化落地(iOS混淆|IPA加固|无源码混淆|Ipa Guard|Swift Shield)
android·ios·小程序·https·uni-app·iphone·webview
雨白5 小时前
让协程更健壮:全面的异常处理策略
android·kotlin
Jeled6 小时前
AI: 生成Android自我学习路线规划与实战
android·学习·面试·kotlin
游戏开发爱好者87 小时前
如何系统化掌握 iOS 26 App 耗电管理,多工具协作
android·macos·ios·小程序·uni-app·cocoa·iphone
shaominjin1237 小时前
android在sd卡中可以mkdir, 但是不可以createNewFile
android·开发语言·python
AI科技星8 小时前
垂直原理:宇宙的沉默法则与万物运动的终极源头
android·服务器·数据结构·数据库·人工智能
阿里云云原生9 小时前
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
开源