okhttp源码简单流程分析
拦截器详细解析可以看大佬简书 "https://www.jianshu.com/p/6fac73f7570f"和 “https://www.jianshu.com/p/3c740829475c”

okhttp请求流程
1:OkHttpClient okHttpClient = new OkHttpClient.Builder()
构建一个okhttpClient对象,传入你想传入的对象,不传就是默认的;
2:构建request对象
Request request = new Request.Builder()
3:okHttpClient.newCall 实际上返回的realCall类 继续调用RealCall.newRealCall
4:调用enqueue方法,传入我们需要的回调接口,而且会判断,
synchronized (this) {
if (executed) throw new IllegalStateException(“Already Executed”);
executed = true;
}
如果当前这个call对象已经被运行的话,则抛出异常;
5:继续调用dispatcher的enqueue方法,如果当前运行队列<64并且正在运行,访问同一个服务器地址的请求<5
就直接添加到运行队列,并且开始运行;
不然就添加到等待队列;
6:运行AsyncCall,调用它的execute方法
7:在execute方法中处理完response之后,会在finally中调用dispathcer的finished方法;
8:当当前已经处理完毕的call从运行队列中移除掉;并且调用promoteCalls方法
9:promoteCalls方法中进行判断,
如果运行队列数目大于等于64,如果等待队列里啥都没有,也直接return?
循环等待队列,
将等待队列中的数据进行移除,移除是根据运行队列中还能存放多少来决定;
移到了运行队列中,并且开始运行;
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();Request request = new Request.Builder().build();//newCall方法是调用RealCall的newRealCall返回一个RealCallCall call = okHttpClient.newCall(request);//执行请求call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, Response response) throws IOException {}});//这里第二次执行会直接报IllegalStateException错误并提示Already Executedcall.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, Response response) throws IOException {}});
进入call.enqueue方法
@Override public void enqueue(Callback responseCallback) {//这个锁是为了防止重复请求 如果你同一个call enqueue多次就会直接返回Already Executedsynchronized (this) {if (executed) throw new IllegalStateException("Already Executed");executed = true;}captureCallStackTrace();eventListener.callStart(this);//这里的enqueue是传入任务线程AsyncCall并分配到运行队列或等待队列client.dispatcher().enqueue(new AsyncCall(responseCallback));}
进入enqueue方法
//okhttp里执行任务分为两个队列 运行队列和等待队列
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);}}
public synchronized ExecutorService executorService() {if (executorService == null) {//1:核心线程数 保持在线程池中的线程数量//2:线程池最大可容纳的线程数 //3参数:当线程池中的线程数量大于核心线程数,空闲线程就会等待60s才会被终止,如果小于就会立刻停止;executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));}return executorService;}
//这个就是队列中传入的线程NameRunnable继承自Runnable
final class AsyncCall extends NamedRunnable {private final Callback responseCallback;AsyncCall(Callback responseCallback) {super("OkHttp %s", redactedUrl());this.responseCallback = responseCallback;}String host() {return originalRequest.url().host();}Request request() {return originalRequest;}RealCall get() {return RealCall.this;}//这个就是Async的run方法@Override protected void execute() {boolean signalledCallback = false;try {//getResponseWithInterceptorChain() 添加拦截器 okhttp的责任链设计也在这里//response就是请求结果Response response = getResponseWithInterceptorChain();//判断重试/重定向拦截器是否被关闭if (retryAndFollowUpInterceptor.isCanceled()) {signalledCallback = true;responseCallback.onFailure(RealCall.this, new IOException("Canceled"));} else {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 {eventListener.callFailed(RealCall.this, e);responseCallback.onFailure(RealCall.this, e);}} finally {//将执行完成的任务从队列中移除client.dispatcher().finished(this);}}}
添加拦截器
//添加拦截器 责任链设计
//拦截器详细解析可以看大佬简书 "https://www.jianshu.com/p/6fac73f7570f"和 "https://www.jianshu.com/p/3c740829475c"
Response getResponseWithInterceptorChain() throws IOException {// Build a full stack of interceptors.List<Interceptor> interceptors = new ArrayList<>();interceptors.addAll(client.interceptors());//重试/重定向拦截器 连接失败后进行重试、对请求结果跟进后进行重定向interceptors.add(retryAndFollowUpInterceptor);//桥拦截器:连接应用程序和服务器的桥梁,我们发出的请求会经过它的处理才能发给服务器,//比如设置请求内容的长度 封装header属性 host keep-live gzip header 进行基本设置,interceptors.add(new BridgeInterceptor(client.cookieJar()));//缓存拦截器 在发出请求前,先判断是否命中缓存,//如果命中则可以不请求,直接使用缓存的响应(默认只会对Get请求进行缓存);//如果未命中则进行网络请求,并将结果缓存,等待下次请求被命中。interceptors.add(new CacheInterceptor(client.internalCache()));//连接拦截器 与服务器建立连接。interceptors.add(new ConnectInterceptor(client));if (!forWebSocket) {interceptors.addAll(client.networkInterceptors());}//与服务器通信;封装请求数据与解析响应数据(如:HTTP报文)。interceptors.add(new CallServerInterceptor(forWebSocket));Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,originalRequest, this, eventListener, client.connectTimeoutMillis(),client.readTimeoutMillis(), client.writeTimeoutMillis());//执行拦截器return chain.proceed(originalRequest);}
在execute方法中处理完response之后,会在finally中调用dispathcer的finished方法;
//将当前已经处理完毕的call从运行队列中移除掉;并且调用promoteCalls方法
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {int runningCallsCount;Runnable idleCallback;synchronized (this) {if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");if (promoteCalls) promoteCalls();runningCallsCount = runningCallsCount();idleCallback = this.idleCallback;}if (runningCallsCount == 0 && idleCallback != null) {idleCallback.run();}}
promoteCalls方法中进行判断
//如果运行队列数目大于等于64,如果等待队列里啥都没有,也直接return
//循环等待队列,
//将等待队列中的数据进行移除,移除是根据运行队列中还能存放多少来决定;
//移到了运行队列中,并且开始运行;private void promoteCalls() {if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {AsyncCall call = i.next();if (runningCallsForHost(call) < maxRequestsPerHost) {i.remove();runningAsyncCalls.add(call);executorService().execute(call);}if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.}}
相关文章:
okhttp源码简单流程分析
拦截器详细解析可以看大佬简书 "https://www.jianshu.com/p/6fac73f7570f"和 “https://www.jianshu.com/p/3c740829475c” okhttp请求流程 1:OkHttpClient okHttpClient new OkHttpClient.Builder() 构建一个okhttpClient对象,传入你想传入的…...
SpringBoot整合Shiro实现登录认证,鉴权授权
文章目录 前言一、shiro简介二、环境搭建2.1.数据库2.1.1user用户表2.1.2user_role用户角色关系表2.1.3role角色表2.1.4role_permission角色权限关系表2.1.5permission权限表 2.2导坐标2.3实体类2.3.1User2.3.2Role2.3.3Permission 2.4MVC三层2.4.1User2.4.1.1mapper层2.4.1.2s…...
Airbnb开源数据可视化工具Visx
一、什么是visx visx 是用于 React 的富有表现力的底层可视化组件集合,结合了 d3 的强大功能来生成可视化,以及 React 更新 DOM 的诸多优势。 在 Airbnb 内部,visx 的目标是统一整个公司的可视化堆栈,在此过程中,创建了 visx 项目,从而有效的将 D3 的强大功能与 React …...
VR仿真实训系统编辑平台赋予老师更多自由和灵活性
为了降低院校教师在VR虚拟现实方面应用的门槛,VR公司深圳华锐视点融合多年的VR虚拟仿真实训系统制作经验,制作了VR动物课件编辑器,正在逐渐受到师生们的关注和应用。 简单来说,VR畜牧专业课件编辑器是一种可以制作虚拟现实动物教学…...
父类对象转成子类对象
import org.springframework.beans.BeanUtils; import java.util.ArrayList; import java.util.List; public class Test {public static void main(String[] args) {List<B> bList new ArrayList<>();B b new B("a","这是a","b",…...
Spring Boot中如何使用Flyway进行数据库迁移
在本文中,我们将了解如何使用 Flyway 来管理 Spring Boot 应用程序中的 SQL 数据库架构。 在本文中,我们将了解如何使用 Flyway 来管理Spring Boot应用程序中的SQL 数据库架构。 Flyway是一个数据库迁移工具,它提供迁移历史和回滚的功能&…...
web在线编辑器(vue版)
目录 前言一、monaco-editor1、源码2、体积优化 二、ace-editor?1、源码2、体积优化 总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多…...
【论文阅读】 Model Sparsity Can Simplify Machine Unlearning
Model Sparsity Can Simplify Machine Unlearning 背景主要内容Contribution Ⅰ:对Machine Unlearning的一个全面的理解Contribution Ⅱ:说明model sparsity对Machine Unlearning的好处Pruning方法的选择sparse-aware的unlearning framework Experiments…...
Spring Clould 部署 - Docker
视频地址:微服务(SpringCloudRabbitMQDockerRedis搜索分布式) 初识Docker-什么是Docker(P42,P43) 微服务虽然具备各种各样的优势,但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&…...
linux--链表动态创建
头插法: 核心代码: s->next head->next; head->next s; 尾插法 核心代码: tail head; s->next NULL; tail->next s; tail s; 当用头插法依次插入值分别为1,2,3,4,5的结点后, 单链表顺序为: he…...
iBooker 布客技术评论 20230818
一、程序员自检手册 为了避免焦虑,你首先需要做的就是梳理你的业务: (1)你所在的行业是轻资产还是重资产? 重资产就是人绕着机器转,创业需要买一大堆设备。如果是重资产,赶紧换一个。 &…...
CK-A60180、CK-B1542、CK-L3095单向离合器
CK-A1542、CK-A1747、CK-A2052、CK-A2652、CK-A3072、CK-A3580、CK-A4090、CK-A45100、CK-A450110、CK-A60130、CK-A65140、CK-A70150、CK-A75160、CK-A80170、CK-A1250、CK-A1855、CK-A2060、CK-A2563、CK-A2563T、CK-A2870、CK-A3080T、CK-A3585、CK-A35100、CK-A35140、CK-A…...
单因素多变量方差分析
多变量方差分析:是对多个独立变量是否受单个或多个因素影响而进行的方差分析。它不仅能够分析多个因素对观测变量的独立影响,更能够分析多个因素的交互作用能否对观测变量产生影响。本章以单因素多变量分析为例,即一个分组变量和多个欲分析的…...
Python Web:Django、Flask和FastAPI框架对比
原文:百度安全验证 Django、Flask和FastAPI是Python Web框架中的三个主要代表。这些框架都有着各自的优点和缺点,适合不同类型和规模的应用程序。 1. Django: Django是一个全功能的Web框架,它提供了很多内置的应用程序和工具&am…...
【CI/CD】Rancher K8s
Rancher & K8s Rancher 和 K8s 的关系是什么?K8s 全称为 Kubernetes,它是一个开源的,用于管理云平台中多个主机上的容器化的应用。而 Rancher 是一个完全开源的企业级多集群 Kubernetes 管理平台,实现了 Kubernetes 集群在混合…...
nodejs 之 express 实现下载网络图片并上传到七牛云对象存储oss空间
为方便阅读,本文将所有逻辑放在一个函数里,可根据自己的情况拆分。 安装依赖 在项目根目录下运行以下命令安装依赖 npm install express qiniu axios业务逻辑 在项目根目录下创建一个名为 app.js 的文件,并添加以下内容 const express re…...
综合能源系统(7)——综合能源综合评估技术
综合能源系统关键技术与典型案例 何泽家,李德智主编 综合能源系统是多种能源系统非线性耦合的、多时间与空间尺度耦合的“源-网-荷一储”一体化系统,通过能源耦合、多能互补,能够实现能源的高效利用,并提高新能源的利用水平。对…...
【JS 线性代数算法之向量与矩阵】
线性代数算法 一、向量的加减乘除1. 向量加法2. 向量减法3. 向量数乘4. 向量点积5. 向量叉积 二、矩阵的加减乘除1. 矩阵加法2. 矩阵减法3. 矩阵数乘4. 矩阵乘法 常用数学库 线性代数是数学的一个分支,用于研究线性方程组及其解的性质、向量空间及其变换的性质等。在…...
配置 yum/dnf 置您的系统以使用默认存储库
题目 给系统配置默认存储库,要求如下: YUM 的 两 个 存 储 库 的 地 址 分 别 是 : ftp://host.domain8.rhce.cc/dvd/BaseOS ftp://host.domain8.rhce.cc/dvd/AppStream vim /etc/yum.repos.d/redhat.repo [base] namebase baseurlftp:/…...
Docker容器与虚拟化技术:Docker资源控制、数据管理
目录 一、理论 1.资源控制 2.Docker数据管理 二、实验 1.Docker资源控制 2.Docker数据管理 三、问题 1.docker容器故障导致大量日志集满,造成磁盘空间满 2、当日志占满之后如何处理 四、总结 一、理论 1.资源控制 (1) CPU 资源控制 cgroups࿰…...
5分钟快速上手:通达信缠论量化插件完整使用指南
5分钟快速上手:通达信缠论量化插件完整使用指南 【免费下载链接】Indicator 通达信缠论可视化分析插件 项目地址: https://gitcode.com/gh_mirrors/ind/Indicator 通达信缠论量化插件是一款专为股票投资者设计的缠论技术分析工具,能够将复杂的缠论…...
告别30秒等待!优化C# BLE设备搜索,Win10下3秒快速发现蓝牙锁(附核心代码对比)
告别30秒等待!优化C# BLE设备搜索,Win10下3秒快速发现蓝牙锁(附核心代码对比) 在物联网设备快速普及的今天,低功耗蓝牙(BLE)技术因其低能耗、低成本的特点,成为智能锁、可穿戴设备等…...
2026年株洲老人小孩都能用专业床垫有哪些?
引言随着生活水平的提高,人们对床垫的要求也越来越高。特别是对于老人和小孩这两类特殊人群,选择一款合适的床垫尤为重要。本文将介绍几款适合老人和小孩使用的专业床垫,其中包括德国美得丽(Musterring)床垫。德国美得…...
Yaade与Postman对比:为什么自托管是更好的选择
Yaade与Postman对比:为什么自托管是更好的选择 【免费下载链接】yaade Yaade is an open-source, self-hosted, collaborative API development environment. 项目地址: https://gitcode.com/gh_mirrors/ya/yaade 在当今API开发领域,选择合适的工…...
LLM-PDF开源工具:高质量文档解析与结构化处理实战指南
1. 项目概述:当LLM遇上PDF,一个开源工具如何重塑文档处理流程最近在折腾一个项目,需要让大语言模型(LLM)去理解一批技术规格书和合同文档。这事儿听起来简单,不就是把PDF扔给模型,让它读吗&…...
光学邻近校正(OPC)技术:原理、优化与应用
1. 光学邻近校正技术概述在半导体制造的光刻工艺中,光学邻近效应(Optical Proximity Effect)是影响图案转移精度的主要挑战之一。当特征尺寸缩小到45nm及以下节点时,光衍射和光阻化学反应导致的图案失真变得尤为显著。具体表现为&…...
XYBotV2:开发者如何快速构建可扩展的智能对话机器人框架
1. 项目概述:一个面向开发者的智能对话机器人框架最近在GitHub上看到一个挺有意思的项目,叫XYBotV2。乍一看标题,可能很多人会以为这又是一个普通的聊天机器人,但如果你点进去仔细研究一下,就会发现它其实是一个为开发…...
如何轻松下载B站4K大会员视频?这款开源工具让你三步搞定离线收藏
如何轻松下载B站4K大会员视频?这款开源工具让你三步搞定离线收藏 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 想象一下…...
AI治理实战:从公平性、可解释性到MLOps全流程落地
1. 项目概述与核心价值最近在整理开源项目时,发现了一个名为“AI_governance”的仓库,作者是bhavya7995。这个标题立刻引起了我的兴趣。在AI技术飞速渗透到各行各业,从代码生成到内容创作,从自动驾驶到医疗诊断的今天,…...
Arm调试寄存器架构详解与应用实践
1. Arm调试寄存器架构概述在Armv8/v9处理器架构中,调试寄存器是实现硬件级调试功能的核心组件。这些寄存器通过外部调试接口(External Debug Interface)为开发人员提供了对处理器内部状态的访问和控制能力。调试寄存器主要分为两类࿱…...
