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);
    }
  }
}
相关推荐
liugddx13 分钟前
Qwen2-VL:发票数据提取、视频聊天和使用 PDF 的多模态 RAG 的实践指南
人工智能·gpt·ai·pdf·开源·音视频
sunly_1 小时前
Flutter:InheritedWidget数据共享
android·javascript·flutter
Q8137574601 小时前
智能算法引领金融创新:正大科技的智能分析框架
android·开发语言·kotlin
张铁铁是个小胖子2 小时前
整合seata遇到的问题
android
亥时科技2 小时前
商城小程序(源码+文档+部署+讲解)
java·小程序·开源·源代码管理
一航jason4 小时前
Android Jetpack Compose 现有Java老项目集成使用compose开发
android·java·android jetpack
猿小蔡-Cool4 小时前
Android 中的 Zygote 和 Copy-on-Write 机制详解
android·zygote
顾北川_野4 小时前
android 默认关闭增强型4GLTE开关;去掉VT视频通话功能及菜单
android·开发语言
海绵波波1074 小时前
聊天服务器(7)数据模块
android·服务器·adb
软件聚导航5 小时前
uniapp 实现 ble蓝牙同时连接多台蓝牙设备,支持app、苹果(ios)和安卓手机,以及ios连接蓝牙后的一些坑
android·ios·uni-app