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.}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/98823.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023国赛数学建模D题思路模型代码 高教社杯

本次比赛我们将会全程更新思路模型及代码&#xff0c;大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022国赛c题matlab_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛c题matlab_UST数模社…

【IEEE会议】第二届IEEE云计算、大数据应用与软件工程国际学术会议 (CBASE2023)

第二届IEEE云计算、大数据应用与软件工程国际学术会议 (CBASE2023&#xff09; 随着大数据时代的到来&#xff0c;对数据获取的随时性和对计算的需求也在逐渐增长。为推动大数据时代的云计算与软件工程的发展&#xff0c;促进该领域学术交流&#xff0c;在CBASE 2022成功举办的…

人工智能在网络安全中的应用: 分析人工智能、机器学习和深度学习等技术在预测、检测和应对网络攻击中的作用

第一章&#xff1a;引言 随着信息技术的迅猛发展&#xff0c;网络安全已成为当今社会不容忽视的重要议题。网络攻击手法日益复杂&#xff0c;传统的防御方法已经不再足够。在这一背景下&#xff0c;人工智能&#xff08;AI&#xff09;技术正逐渐崭露头角&#xff0c;为网络安…

循环神经网络RNN完全解析:从基础理论到PyTorch实战

目录 一、循环神经网络全解1.1 什么是循环神经网络网络结构工作原理数学模型RNN的优缺点总结 1.2 循环神经网络的工作原理RNN的时间展开数学表述信息流动实现示例梯度问题&#xff1a;梯度消失和爆炸总结 1.3 循环神经网络的应用场景文本分析与生成1.3.1 自然语言处理1.3.2 机器…

unity打造路径编辑与导航系统

Unity是一款非常流行的游戏引擎&#xff0c;它提供了丰富的工具和API&#xff0c;方便开发者快速创建游戏。其中&#xff0c;路径编辑与导航系统是游戏开发中非常重要的一部分&#xff0c;可以帮助玩家更好地探索游戏世界&#xff0c;提升游戏体验。本文将详细介绍如何在Unity中…

C#与西门子PLC1500的ModbusTcp服务器通信2--ModbusTcp协议

Modbus TCP是近年来越来越流行的工业控制系统通信协议之一&#xff0c;与其他通信协议相比&#xff0c;Modbus TCP通信速度快、可靠性高、兼容性强、适用于模拟或数字量信号的传输&#xff0c;阅读本文前你必须比较熟悉Modbus协议&#xff0c;了解tcp网络。 一、什么是Modbus …

自动驾驶合成数据科普一:不做真实数据的“颠覆者”,做“杠杆”

前言&#xff1a; 在7月底的一篇文章中&#xff0c;九章智驾提到&#xff0c;数据闭环能力是自动驾驶下半场的“入场券”&#xff0c;这一观点在行业内引起了广泛共鸣。 在数据闭环体系中&#xff0c;仿真技术无疑是非常关键的一环。仿真的起点是数据&#xff0c;而数据又分为真…

Linux网络编程:网络基础

文章目录&#xff1a; 一&#xff1a;协议 二&#xff1a;网络应用设计模式_BS模式和CS模式 三&#xff1a;网络分层模型&#xff08;OSI七层 TCP/IP四层&#xff09; 四&#xff1a;通信过程 五&#xff1a;协议格式 1.数据包封装 2.以太网帧格式和ARP数据报格式 …

【HarmonyOS】【DevEco Studio】ohpm安装失败该如何解决?

【关键词】 HarmonyOS、DevEco Studio、ohpm安装失败 【问题背景及解决方案】 最近遇到很多DevEco Studio安装ohpm失败的问题&#xff0c;下面给大家介绍几种出现的问题以及解决方案&#xff1a; 1、ohpm not set up&#xff0c;报错截图如下&#xff1a; ​ 解决方案&…

基于YOLOv8模型和PCB电子线路板缺陷目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型PCB电子线路板缺陷目标检测系统可用于日常生活中检测与定位PCB线路板瑕疵&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检…

❤ 全面解析若依框架vue2版本(springboot-vue前后分离--前端部分)

❤ 解析若依框架之前台修改 1、修改页面标题和logo 修改网页上的logo ruoyi-ui --> public --> favicon.ico&#xff0c;把这个图片换成你自己的logo 修改网页标题 根目录下的vue.config.js const name process.env.VUE_APP_TITLE || ‘若依管理系统’ // 网页标题 换成…

基于ssm的CRM客户管理系统(spring + springMVC + mybatis)营销业务信息java jsp源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于ssm的CRM客户管理系统&#xff08;spring spring…

通过postgresql的Ltree字段类型实现目录结构的基本操作

通过postgresql的Ltree字段类型实现目录结构的基本操作 将这种具有目录结构的excel表存储到数据库中&#xff0c;可以采用树型结构存储 DROP TABLE IF EXISTS "public"."directory_tree"; CREATE TABLE "public"."directory_tree" (…

【李沐】3.5、softmax回归的从0开始实现

注意&#xff1a; 把每个像素位置看作⼀个特征 # 导入PyTorch库 import torch # 从IPython库中导入display模块&#xff0c;用于在交互式环境中显示内容 from IPython import display # 从d2l.torch模块中导入torch作为d2l的别名&#xff0c;方便后续使用d2l库中的功能 from d…

rabbitMq安装后无法启动可视化页面http://localhost:15672处理

本次安装环境信息&#xff1a; 系统&#xff1a;win10 64位专业版 erlang&#xff1a;otp_win64_23.0 rabbitMQ&#xff1a;rabbitmq-server-3.8.5 安装rabbitMQ需要依赖erlang语言环境&#xff0c;所以需要我们下载erlang的环境安装程序。 一、下载安装程序 rabbitMQ安装…

UGUI可视化组件Image, RawImage

一.组件Image 1.1 Image的属性 创建的Image对象自带Image组件&#xff0c;用来显示图片&#xff0c;其属性说明如下 属性&#xff1a;功能&#xff1a;Source Image表示要显示的图像的纹理&#xff08;必须作为精灵导入&#xff09;。Color要应用于图像的颜色&#xff0c;会和…

Matlab论文插图绘制模板第108期—特征渲染的标签散点图

在之前的文章中&#xff0c;分享了Matlab标签散点图的绘制模板&#xff1a; 进一步&#xff0c;再来分享一下特征渲染的标签散点图的绘制模板&#xff0c;以便再添加一个维度的信息。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中…

Vue-13.创建完整的Vue项目(vue+vue-cli+js)-1

前言 之前写了命令创建Vue项目&#xff0c;但是事实上我们可以直接用编译器直接创建项目&#xff0c;这里我使用webstorm&#xff08;因为我是前后端兼修的所以我习惯使用Idea家族的编译器&#xff09; 只写前端的推荐用VsCode前后端都写的推荐用webstorm 新建项目 项目初始…

框架分析(1)-IT人必须会

框架分析&#xff08;1&#xff09;-IT人必须会 专栏介绍当今主流框架前端框架后端框架移动应用框架数据库框架测试框架 Angular关键特点和功能&#xff1a;组件化架构双向数据绑定依赖注入路由功能强大的模板语法测试友好 优缺点分析优点缺点 总结 专栏介绍 link 主要对目前市…

爱荷华州的一个学区正在使用ChatGPT来决定禁止哪些书籍

为了响应爱荷华州最近颁布的立法&#xff0c;管理员们正在从梅森市学校图书馆移除禁书&#xff0c;官员们正在使用ChatGPT帮助他们挑选书籍&#xff0c;根据公报和大众科学. 由州长金雷诺兹签署的禁令背后的新法律是教育改革浪潮的一部分&#xff0c;共和党立法者认为这是保护…