OkHttp 3.14.10源码分析(2)- OkHttpClient - OkHttp的“ApplicationContext”

2024-01-22 16:08

本文主要是介绍OkHttp 3.14.10源码分析(2)- OkHttpClient - OkHttp的“ApplicationContext”,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

在上一篇文章《OkHttp总体框架介绍》中,我简单的介绍了一下我对OkHttp总体架构设计的一个理解,在文章中,我对OkHttp的各个层次和各个关键的类都做了一个简单的介绍。那这一章节开始,我就开始从更加详细的角度去分析这些关键类的源码,那首当其冲的就是OkHttpClient。

OkHttpClient可以看作是OKHTTP的一个全局应用上下文,在一个应用中往往只会创建一个单例。它主要有两个功能

  • 可配置、存储和获取一些全局的属性配置,比如超时时间、自定义的CookieJar实现、自定义的Interceptor实现、添加事件监听等等。
  • 负责创建和管理一些全局单例对象,比如Dispatcher、ConnectionPool等。
  • 提供newCall API,我们用的最多也是这个API,例如
    String respJson = okHttpClient.newCall(request).execute().body().string();

     

OKhttpClient中大部分的代码都是其属性的配置,并没有什么逻辑上的实现,所以下面我们就从其各个属性开始,去逐步了解OKhttpClient的源码。 

属性

对于OkHttp的属性,我主要根据其特性和层次对其进行分类。但是这里不会出现上一篇文章架构图中描绘的所有类,因为那图中的类或者接口不是所有都对外开放的,一些是内部使用的API,例如:Transmitter、Exchange、Connection这些都不会出现在OKHttpClient中。

基础配置

这些属性主要是一些全局性的基础配置,它们中大部分都是对用户开放的,可获取可设置。它们会存储在OkHttp实例当中,并且会在全局范围内被各个层次的模块使用,主要是用来控制通信的一些基本行为,比如请求超时时间,是否SSL重定向,是否Http重定向,是否使用缓存、支持的协议等。

//协议簇-只支持HTTP_2/HTTP_1_1,并且不可修改
static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(Protocol.HTTP_2/, Protocol.HTTP_1_1);
//默认连接规范
//ConnectionSpec.CLEARTEXT:Http的规范配置
//ConnectionSpec.MODERN_TLS:TLS规范配置
static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(ConnectionSpec.MODERN_TLS,ConnectionSpec.CLEARTEXT);
//是否SSL重定向
final boolean followSslRedirects;
//是否http重定向
final boolean followRedirects;
//请求超时(connect + write + read)默认没限制
final int callTimeout;
//连接超时(对应tcp connect())
final int connectTimeout;
//读取超时(对应TCP read())默认10s
final int readTimeout;
//写入超时(对应TCP write())默认10s
final int pingInterval;
//ping周期
final int writeTimeout;

线程资源管理层

这一层次的类只有Dispatcher一个。

final Dispatcher dispatcher;

OkHttpClient.Buider会使用其的无参构造函数创建一个默认的实现,无参构造函数会使用内置的线程池来执行异步任务。

public Builder() {dispatcher = new Dispatcher();...
}

Dispatcher主要是实现异步请求任务策略,负责分配异步线程资源,控制异步连接数,只覆盖线程资源层面的逻辑,往下的执行过程对其来说是透明的。对于同步任务,Dispatcher只是简单记录当前运行的任务实体(RealCall),并且是由RealCall主动注册和注销。
你可以通过OkHttpClient.Builder和Dispatvher有参构造函数来指定执行异步任务的线程池。

//这里出于演示目的,只是创建了一个简单的线程池,真正使用需要用户根据自己的应用场景配置自己的线程池。
Executor executor = Executors.newSingleThreadExecutor();
OkHttpClient client = new OkHttpClient.Builder().dispatcher(new Dispatcher(executor)).build();

应用层协议(Http)实现

//用户自定义拦截器,默认为空,会被添加到Interceptor调用链的最前端
final List<Interceptor> interceptors;
//用户自定义拦截器,默认为空,拦截所有非WebSocket的请求和响应。
//该集合会被添加到Connect完成后和数据发送前的中间
final List<Interceptor> networkInterceptors;
//自定义CookieJar,系统默认只有一个空实现,如果用户想实现Cookie功能,需要自己实现该接口,并且设置到OKHttpClient中。
final CookieJar cookieJar;
//实现了Http协议的缓存规范,默认为空。
final @Nullable Cache cache;

连接池

//连接池
final ConnectionPool connectionPool;

ConnectionPool是一个final类,同时它并没有实现连接池的功能,而是委派给RealConnectionPool来实现:

public final class ConnectionPool {final RealConnectionPool delegate;//默认参数public ConnectionPool() {this(5, 5, TimeUnit.MINUTES);}//用户可以通过该构造方法指定一些线程池的配置参数public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {this.delegate = new RealConnectionPool(maxIdleConnections, keepAliveDuration, timeUnit);}//下面三个方法都是通过委派给RealConnection实例完成public int idleConnectionCount() {return delegate.idleConnectionCount();}...
}

ConnectionPool 虽然是不可扩展的,但是你可以通过这样的方式修改ConnectionPool 的默认参数:

OkHttpClient okHttpClient = new OkHttpClient().newBuilder()//最大空闲连接数是10,空闲连接存活时间是15分钟.connectionPool(new ConnectionPool(10,15, TimeUnit.MINUTES)).build();

传输层

//代理服务设置,默认为空
final @Nullable Proxy proxy;
//代理选择器,默认为空
//对于Proxy和ProxySelector的使用,小伙伴可以参考JDK官方文档,机翻一下应该看懂也不难。
//https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html
final ProxySelector proxySelector;
//Socket工厂类,默认为DefaultSocketFactory。你可以自定义自己的SocketFacotry。
final SocketFactory socketFactory;
//SSLSocket工厂类,默认SSLSocketFactoryImpl,也可以自定义。
final SSLSocketFactory sslSocketFactory;
//SSL主机名验证
final HostnameVerifier hostnameVerifier;
//下面两个是对SSL证书的处理
final CertificateChainCleaner certificateChainCleaner;
final CertificatePinner certificatePinner;
//代理权限认证
final Authenticator proxyAuthenticator;
//代理权限认证
final Authenticator authenticator;
//DNS解析
final Dns dns;

内部使用类

static {//OKHttp内部类,主要代理了一些OKHttp重用的内部API,//方便后序OKHttp升级,如果后期某个API从语义上改变了,只需要修改Internal里面相应的代理方法即可Internal.instance = new Internal() {...}
}

总结

到这里,我们就对OkHttpClient进行了一遍初略的了解,了解它到底有哪些属性,并对这些属性的作用进行了一个简单的归类,同时指出了哪些是可以自定义扩展和配置的。
在后面我们会对OkHttp其他的一些关键的实现类,进行详细的源码分析,如果文章有什么问题,也欢迎大家指出。

这篇关于OkHttp 3.14.10源码分析(2)- OkHttpClient - OkHttp的“ApplicationContext”的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/633490

相关文章

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An