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);
    }
  }
}
相关推荐
李斯维4 分钟前
Android 沉浸式(Edge-to-Edge)的介绍与应用
android·android jetpack
恋猫de小郭8 分钟前
AndroidX 将引入有全新 AppState ,用于管理 Compose 状态
android·前端·flutter
Zender Han8 分钟前
Flutter 轻量存储方案介绍、区别、对比和使用场景
android·flutter·ios
黄林晴13 分钟前
Google Play 强制截止,内购应用必须升级 Billing 8,不改无法更新
android
zhangphil16 分钟前
Android RecyclerView+Coil解码Bitmap设置进View,RenderThread上屏显示Graphics
android
idingzhi23 分钟前
A股量化策略日报(2026年05月11日)
android·开发语言·python·kotlin
我命由我1234523 分钟前
Jetpack Compose - 设置 Compose 编译器、设置 Compose 依赖项
android·java·java-ee·kotlin·android jetpack·android-studio·android runtime
Bnews35 分钟前
开源AIoT平台如何重塑扫地机器人开发格局
机器人·开源
API开发平台36 分钟前
开源 API 开发平台 4.5.0 发布
低代码·开源
Kapaseker42 分钟前
reified 如何骗过 JVM 类型擦除
android·kotlin