OKhttp-基本工作流程责任链模式原理

news2024/11/30 6:44:10

OKhttp工作的大致流程

整体流程

(1)、当我们通过OkhttpClient创立一个okHttpClient 、Request 、Call,并发起同步或者异步请求时;

(2)、okhttp会通过Dispatcher对我们所有的Call(RealCall实现类)进行统一管理,并通过execute()及enqueue()方法对同步或者异步请求进行执行; (3)、execute()及enqueue()这两个方法会最终调用RealCall中的getResponseWithInterceptorChain()方法,从阻拦器链中获取返回结果; (4)、拦截器链中,依次通过ApplicationInterceptor应用拦截器、RetryAndFollowUpInterceptor(重定向阻拦器)、BridgeInterceptor(桥接阻拦器)、CacheInterceptor(缓存阻拦器)、ConnectInterceptor(连接阻拦器)、NetwrokInterceptor(网络拦截器)、CallServerInterceptor(请求阻拦器)对请求依次处理,与服务的建立连接后,获取返回数据,再经过上述阻拦器依次解决后,最后将结果返回给调用方。

提供两张图便于了解和记忆:
在这里插入图片描述

okhttp整体流程1

在这里插入图片描述

OkHttp Response的返回整体流程属于责任链模式,本篇文章重点分析其中的责任链模式。

先说结论:OkHttp中有一个链条类,以及许多节点类,节点可以放在链条上,将需要发送的Request交给链条,启动链条,首节点就可以对Request进行加工并继续向下传递,最后一个节点将请求发出,当最后一个节点收到Response后,逐步向上传递,最终回到首节点。

流程如下图:

在这里插入图片描述

黑线代表Request的流向,红线代表Response的流向,在流向的过程中上游可以对下游的Request或Response进行加工处理。

在OkHttp原理第一篇—使用与分发机制中我们得出结论,无论异步请求还是同步请求,Response都是调用RealCall中的 getResponseWithInterceptorChain()方法返回的,因此我们在从方法开始分析。

RealCall#getResponseWithInterceptorChain

@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
    // Build a full stack of interceptors.
    //初始化拦截器数组
    val interceptors = mutableListOf<Interceptor>()
    interceptors += client.interceptors //用户自定义的节点,可在构建Client时加入自己的节点
    interceptors += RetryAndFollowUpInterceptor(client)
    interceptors += BridgeInterceptor(client.cookieJar)
    interceptors += CacheInterceptor(client.cache)
    interceptors += ConnectInterceptor
    //是否属于webSocket协议链接,若是则添加networkInterceptors
    if (!forWebSocket) {
        interceptors += client.networkInterceptors
    }
    interceptors += CallServerInterceptor(forWebSocket)
    
    //创建Chain链条
    val chain = RealInterceptorChain(
        call = this,                                        //当前请求的Call(Request的载体)
        interceptors = interceptors,                        //节点数组
        index = 0,                                          //目前需要执行的节点下标
        exchange = null,    
        request = originalRequest,                          //原先的请求,后续会对请求进行再次封装
        connectTimeoutMillis = client.connectTimeoutMillis, //超时时间
        readTimeoutMillis = client.readTimeoutMillis,
        writeTimeoutMillis = client.writeTimeoutMillis
    )
    ...
    
    //链条执行,下面分析
    val response = chain.proceed(originalRequest)
    
    ...
    return response
    
    ...
​
}

以HTTP请求分析,去掉自定义节点,此时链条会存在5个节点(在OkHttp中节点叫做拦截器,下文中全部使用拦截器):

  • RetryAndFollowUpInterceptor 重试与重定向拦截器,主要处理错误信息进行重试和重定向操作
  • BridgeInterceptor 桥接拦截器,对HTTP请求头进行封装,并处理请求体的压缩
  • CacheInterceptor 缓存拦截器, 处理HTTP的缓存操作
  • ConnectInterceptor 连接拦截器,建立Socket连接
  • CallServerInterceptor请求拦截器,对Socket的输入流和输出流进行操作,真正的请求发起者和相应接收者

上述拦截器的作用还无需理解,此小节重点分析OkHttp的责任链的执行过程。

@Throws(IOException::class)
override fun proceed(request: Request): Response {
    ...
    //创建一个新的链条,使当前下标加1,看下1中分析copy函数
    val next = copy(index = index + 1, request = request)
    val interceptor = interceptors[index]
    @Suppress("USELESS_ELVIS")
    //执行节点的处理,将下标加1的next链条交给当前拦截器,看下2,分析当前节点如何启动下一个节点
    val response = interceptor.intercept(next) ?: throw NullPointerException(
        "interceptor $interceptor returned null")
    ...
​
    return response
}

1.RealInterceptorChain#copy

返回一个新的RealInterceptorChain

internal fun copy(
  index: Int = this.index,
  exchange: Exchange? = this.exchange,
  request: Request = this.request,
  connectTimeoutMillis: Int = this.connectTimeoutMillis,
  readTimeoutMillis: Int = this.readTimeoutMillis,
  writeTimeoutMillis: Int = this.writeTimeoutMillis
) = RealInterceptorChain(call, interceptors, index, exchange, request, connectTimeoutMillis,
    readTimeoutMillis, writeTimeoutMillis)

2.RetryAndFollowUpInterceptor,BridgeInterceptor,CacheInterceptor,ConnectInterceptor#intercept

override fun intercept(chain: Interceptor.Chain): Response {
    val realChain = chain as RealInterceptorChain
    var request = chain.request
    //对Request进行处理
    ...
    //进行递归,回到上的proceed()方法,此时index下标已经+1,执行下一个拦截器的处理
    response = realChain.proceed(request)
    //对response进行处理
    ...
    return response
         
}

前四个拦截器的处理方法类似,第五个拦截器会有所不同,其Response会直接通过网路返回的数据进行构建,不会再往下传递。

以上就是okhttp的基本操作流程与他的责任链模型学习;更多okhttp技术与Android开发技术可以参考《Android核心技术手册》这个技术笔记。

总结:

整理一下上述流程,当调用getResponseWithInterceptorChain()方法后,初始化拦截器和链条,并为链条添加5个节点,后续调用链条的proceed()方法,proceed()会去创建一个新链条,并使下标加1,再执行当前链条的下标位置的拦截器的intercept()方法,并将刚才创建的链条当成参数传入intercept()方法,在拦截器的intercept()方法实现中,又会递归去调用传入链条的proceed()方法,直到链条执行结束。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务的版本号要怎么设计?

今天我们来聊一下微服务项目中的版本号要怎么设计。 小伙伴们平时看到的项目版本号&#xff0c;基本上都是分为了三部分 X.Y.Z&#xff0c;版本升级的时候版本号都会变&#xff0c;那么版本号怎么变&#xff0c;这可不是拍脑门决定的&#xff0c;今天我们就一起来探讨一下这个…

Live800:客户服务的三重境界,你做到了吗?

毋庸置疑&#xff0c;赢得客户的青睐是维系自身经济长青的基础。想要客户满意&#xff0c;得到最佳的客户评价&#xff0c;企业就需要为客户提供超出他们期望的服务。有人将客户服务分为三重境界:第一重境界&#xff0c;把分内的服务做精&#xff1b;第二重境界&#xff0c;把额…

libtorch c++复现cycle gan网络

目录 1. 原论文论文&#xff1a;https://arxiv.org/abs/1703.10593 2. 代码 2.1 下采样 2.2 残差块 2.3 上采样模块 2.4 生成器代码 3. 判别器 3.1 判别器组件 3. 2 判别器 4. 训练 4.1 输入数据 4.2 生成器loss函数结构图 4.3 判别器loss结构图 1. 原论文 论文&…

【java查漏补缺】网络编程

网络编程实际上就是通过套接字进行连接后进行通信&#xff0c;本质还是程序进行IO操作。 所谓套接字&#xff0c;实际上就是IP地址加上端口号的组合&#xff0c;通过套接字&#xff0c;可以连接到网络中某一台计算机的某一个进程。 下面就是客户端和服务器的简单例子&#xf…

vue3-ElmentPlus封装通用表格-含单元格操作-多选-分页器

Sam9029的CSDN博客主页:Sam9029的博客_CSDN博客-JS学习,CSS学习,Vue-2领域博主 **&#x1f431;‍&#x1f409;&#x1f431;‍&#x1f409;恭喜你&#xff0c;若此文你认为写的不错&#xff0c;不要吝啬你的赞扬&#xff0c;求收藏&#xff0c;求评论&#xff0c;求一个大大…

【测试】测试分类

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录测试分类&#xff08;大框架&#xff09;一、按照测试对象划分一&#xff09;可靠性测试二&#xff09;容错性测试三&#xff09;安装卸载测试&#xff08;万能公式中可以加上&#xff09;四&#xff09;内存泄漏测试…

合芯科技携手新享科技联合打造国产化项目管理系统解决方案

北京新享科技有限公司 北京新享科技有限公司&#xff0c;是上海合见工业软件集团控股的子公司。上海合见工业软件集团有限公司是自主创新的高性能工业软件及解决方案提供商&#xff0c;以EDA&#xff08;电子设计自动化&#xff0c;Electronic Design Automation&#xff09;领…

【实际开发03】- dto + vo - 先处理 dto , 后处理 vo ( 通常少一注解 )

目录 0. 建议 : 多用组合 , 少用继承 1. EqualsAndHashCode(callSuper true) - 解决允许调用父类 2. 序列化 ID : private static final long serialVersionUID 1L; 1. serialVersionUID 作用 : 序列化时为了保持版本的兼容性 3. 数据概览 ( 统计 ) : XxxxProfileVO 1.…

CAD常用命令:对象选择过滤器(FILTER)

CAD软件中为了方便绘图&#xff0c;有效地提升绘图效率&#xff0c;提供了很多CAD命令快捷键&#xff0c;而CAD对象选择过滤器作为CAD常见命令之一&#xff0c;在日常的CAD绘图过程中经常能用到&#xff0c;你知道CAD对象选择过滤器怎么用吗&#xff1f;本文小编就来给大家分享…

Qt解析Json数据

目录前言1.下载 jsoncpp 源码2.编译3.JSON数据读写示例4.jsoncpp核心类详解前言 本文主要介绍了使用Qt框架编程时如何解析JSON数据的一种方法。JSON是英文JavaScript Object Notation 的缩写&#xff0c;它是一种轻量级的数据交换格式&#xff0c;具有方便阅读和编写的优点&am…

Jenkins 项目的 gpg: signing failed: Bad passphrase 错误

因为我们项目需要使用 Jenkins 对文件进行签名。但是我们遇到了gpg: signing failed: Bad passphrase错误。原因和解决通常这个问题的原因是 Key 已经配置成功并且已经被命令行找到了。主要原因是你的秘钥密码配置的问题。这个配置有 2 个地方&#xff0c;第一个地方是项目的 P…

2022年度牛奶乳品行业数据:十大热门品牌销量排行榜

当前&#xff0c;随着经济的发展及人民生活水平的提高&#xff0c;牛奶乳品已经日趋成为人们在日常饮食中不可缺少的食物之一&#xff0c;市面上的产品种类也越来越多。并且&#xff0c;随着人们消费习惯的转变&#xff0c;牛奶乳品的消费场景也日益多元化。未来&#xff0c;预…

jdk1.8之函数式接口

l[TOC] 函数式接口概述 jdk1.8 引入了一个核心概念&#xff1a;函数式接口&#xff08;Functional Interface&#xff09;。如果一个接口有且只有一个未实现的方法&#xff0c;那这个接口就称为函数式接口。并且引入了一个新的注解&#xff1a;FunctionalInterface &#xff0…

一、Gradle入门

文章目录一、Gradle入门1.1 Gradle 简介1.2 常见的项目构建工具1.3 Gradle 安装1.3.1 Gradle 安装说明1.3.2 安装 JDK1.3.3 下载并解压到指定目录1.3.4 配置环境变量1.3.5 检测是否安装成功1.4 Gradle 项目目录结构1.5 Gradle 创建第一个项目1.5.1 Gradle 中的常用命令1.5.2 修…

【MySQL进阶教程】视图/存储过程/触发器

前言 本文为 【MySQL进阶教程】视图/存储过程/触发器 相关知识&#xff0c;下边将对视图&#xff0c;存储过程&#xff0c;存储函数&#xff0c;触发器等进行详尽介绍~ &#x1f4cc;博主主页&#xff1a;小新要变强 的主页 &#x1f449;Java全栈学习路线可参考&#xff1a;【…

MySQL高级【存储函数触发器】

1&#xff1a;存储函数1.1&#xff1a;介绍存储函数是有返回值的存储过程&#xff0c;存储函数的参数只能是IN类型的。具体语法如下&#xff1a; CREATE FUNCTION 存储函数名称 ([ 参数列表 ]) RETURNS type [characteristic ...] BEGIN -- SQL语句 RETURN ...; END ;character…

如何管理存量用户?

存量市场的老客户对于企业来说如同一座金矿&#xff0c;好好运营老客户&#xff0c;可以给企业带来源源不断的新客户&#xff0c;企业所获得的收益远比拉新所获收益要高的多。 前言 存量客户是指某个时间段里原先已有的客户&#xff0c;与新增客户相对应&#xff0c;通俗点说&…

Python开发Web扫描器实战

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是Python开发Web扫描器实战。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未…

机器学习--模型评估、过拟合和欠拟合、模型验证

目录 一、模型评估 模型指标 常见关于分类的指标 准确率 精确率(精确度) 召回率 F1 score PR曲线&#xff1a; ROC AUC 二、过拟合和欠拟合 训练与泛化误差的区别 什么样的情况会导致欠拟合与过拟合&#xff1f; 模型的复杂度&#xff08;能够拟合各种各样函…

分组加密模式 ECB CBC OFB CFB

多个分组加密互相之间如何关联 ECB模式 每个分组之间单独加密&#xff0c;互不关联 2个分组明文一样&#xff0c;结果也一样&#xff0c;那么只需爆破其中1个就可以了 每个分组互不关联&#xff0c;可以分段同时来爆破&#xff0c;不安全 可以通过替换某段密文来达到替换明…