原副标题:精辟OkHttp源标识符导出及应用领域课堂教学
译者:vivo 网络伺服器项目组- Tie Qinrui
OkHttp 在 Java 和 Android 当今世界中被广为采用,深入细致自学源标识符有利于掌控应用软件优点和提高程式设计水平。
职责编辑首先从源标识符侧发力概要预测了两个允诺发动过程中的核心理念标识符,接著通过时序和洼瓣归纳地如是说了OkHttp的整体结构,重点预测了圣夫龙的职责链商业模式结构设计,最后列出了OkHttp圣夫龙在项目中的前述应用领域。
一、大背景如是说
在生产课堂教学中,经常会碰到这样的情景:需要特别针对某两类 Http 允诺做标准化的处置,比如在 Header 里加进允诺模块或者修正允诺积极响应之类。这类难题的一种比较典雅的软件系统是采用圣夫龙来对允诺和积极响应做标准化处置。
在 Android 和 Java 当今世界里 OkHttp 凭借着其INS13ZD和可用性被广为采用。作为这款杰出的开放源码 Http 允诺架构,深入细致了解它的实现基本原理,能自学杰出软件的结构设计和代码实战经验,协助他们更快到地采用它的优点,并且有利于特定情景下的难题摸查。职责编辑试著从源标识符起程探求 OkHttp 的基本概念,并列出了两个单纯的范例说明圣夫龙在他们工程项目中的前述应用领域。职责编辑源标识符如前所述 OkHttp 3.10.0。
二、OkHttp 基本概念
2.1 从两个允诺实例起程
OkHttp 能用以推送并行或触发器的允诺,触发器允诺与并行允诺的主要差别是触发器允诺会交予缓存池来运维允诺的继续执行。采用 OkHttp 推送两个并行允诺的标识符十分简约,实例标识符如下表所示:
并行 GET 允诺实例
// 1.建立OkHttpClient应用程序 OkHttpClient client = newOkHttpClient; publicString getSync( String url) throws IOException { OkHttpClient client = newOkHttpClient; // 2.建立两个Request对象 Request request = newRequest.Builder .url(url) .build; // 3.建立两个Call对象并调用execute方法 try(Response response = client.newCall(request).execute) { returnresponse.body. string; } }其中 execute 方法是允诺发动的入口,RealCall 对象的 execute 方法的源标识符如下表所示:
RealCall 的 execute 方法源标识符
@OverridepublicResponse execute throws IOException { synchronized ( this) { // 并行锁定当前对象,将当前对象标记为“已继续执行” if(executed) thrownew IllegalStateException( “Already Executed”); executed = true; } captureCallStackTrace; // 捕获调用栈 eventListener.callStart( this); // 事件监听器记录“调用开始”事件 try{ client.dispatcher.executed( this); // 运维器将当前对象放入“运行中”队列 Response result = getResponseWithInterceptorChain; if(result == null) thrownew IOException( “Canceled”); returnresult; } catch(IOException e) { eventListener.callFailed( this, e); // 异常时记录“调用失败事件” throwe; } finally{ client.dispatcher.finished(this); // 将当前对象从“运行中”队列移除 } }execute 方法首先将当前允诺标记为“已继续执行”,然后会为重试跟踪圣夫龙加进堆栈追踪信息,接著事件监听器记录“调用开始”事件,运维
getResponseWithInterceptorChain 其源标识符如下表所示:
Response getResponseWithInterceptorChain( ) throws IOException { // 构建两个全栈的圣夫龙列表 List<Interceptor> interceptors = newArrayList<>; interceptors.addAll(client.interceptors); interceptors.add(retryAndFollowUpInterceptor); interceptors. add( newBridgeInterceptor(client.cookieJar)); interceptors. add( newCacheInterceptor(client.internalCache)); interceptors. add( newConnectInterceptor(client)); if(!forWebSocket) { interceptors.addAll(client.networkInterceptors); } interceptors. add( newCallServerInterceptor(forWebSocket)); Interceptor.Chain chain = newRealInterceptorChain(interceptors, ……); returnchain.proceed(originalRequest); }该方法中按照特定的顺序建立了两个有序的圣夫龙列表,之后采用圣夫龙列表建立圣夫龙链并发动 proceed 方法调用。在chain.proceed 方法中会采用递归的方式将列表中的圣夫龙串联起来依次对允诺对象进行处置。圣夫龙链的实现是 OkHttp 的两个巧妙所在,在后文他们会用一小节专门讨论。在继续往下预测之前,通过以上的标识符片段他们已经大致看到了两个允诺发动的整体流程。
2.2 OkHttp 核心理念继续执行流程
两个 OkHttp 允诺的核心理念继续执行过程如以下时序所示:
图 2-1 OkHttp允诺继续执行时序
图中各部分的含义和作用如下表所示:
OkHttpClient :是整个 OkHttp 的核心理念管理类,从面向对象的抽象表示上来看它代表了应用程序本身,是允诺的调用工厂,用以推送允诺和读取积极响应。在大多数情况下这个类应该是被共享的,因为每个 Client 对象持有自己的连接池和缓存池。重复建立则会造成在空闲池上的资源浪费。Client对象能通过默认的无参构造方法建立也能通过 Builder 建立自定义的 Client 对象。Client 持有的缓存池和连接池资源在空闲时能自动释放无需应用程序标识符手动释放,在特定情况下也支持手动释放。 Request :两个 Request 对象代表了两个 Http 允诺。它包含了允诺地址 url,允诺方法类型 method ,允诺头 headers,允诺体 body 等属性,该对象具有的属性普遍采用了 final 关键字来修饰,正如该类的说明文档中所述,当这个类的 body 为空或者 body 本身是不可变对象时,这个类是两个不可变对象。 Response :两个 Response 对象代表了两个 Http 积极响应。这个实例对象是两个不可变对象,只有 responseBody 是两个能一次性采用的值,其他属性都是不可变的。 RealCall :两个 RealCall 对象代表了两个准备好继续执行的允诺调用。它只能被继续执行一次。同时负责了运维和职责链组织的两大重任。 Dispatcher :运维器。它决定了触发器调用何时被继续执行,内部采用 ExecutorService 运维继续执行,支持自定义 Executor。 EventListener :事件监听器。抽象类 EventListener 定义了在两个允诺生命周期中记录各种事件的方法,通过监听各种事件,能用以捕获应用领域程序 HTTP 允诺的继续执行指标。从而监控 HTTP 调用的频率和性能。 Interceptor :圣夫龙。对应了应用软件结构设计商业模式中的圣夫龙商业模式,圣夫龙可用于改变、增强应用软件的常规处置流程,该商业模式的核心理念特征是对应用软件系统的改变是透明的和自动的。OkHttp 将整个允诺的复杂逻辑拆分2.3 OkHttp 整体架构
通过进一步阅读 OkHttp 源标识符,能看到 OkHttp 是两个分层的结构。应用软件分层是复杂系统结构设计的常用手段,通过分层能将复杂难题划分成规模更小的子难题,分而治之。同时分层的结构设计也有利于功能的封装和复用。OkHttp 的架构能分为:应用领域接口层,协议层,连接层,缓存层,I/O层。不同的圣夫龙为各个层次的处置提供调用入口,圣夫龙通过职责链商业模式串联成圣夫龙链,从而完成两个Http允诺的完整处置流程。如下表所示图所示:
图 2-2 OkHttp洼瓣(图片来自网络)
2.4 OkHttp 圣夫龙的种类和作用
OkHttp 的核心理念功能是通过圣夫龙来实现的,各种圣夫龙的作用分别为:
client.interceptors :由开发者设置的圣夫龙,会在所有的圣夫龙处置之前进行最早的拦截处置,可用于加进一些公共模块,如自定义 header、自定义 log 之类。 RetryAndFollowUpInterceptor :主要负责进行重试和重定向的处置。 BridgeInterceptor :主要负责允诺和积极响应的转换。把用户构造的 request 对象转换成推送到伺服器 request对象,并把伺服器返回的积极响应转换为对用户友好的积极响应。 CacheInterceptor :主要负责缓存的相关处置,将 Http 的允诺结果放到到缓存中,以便在下次进行相同的允诺时,直接从缓存中读取结果,提高积极响应速度。 ConnectInterceptor :主要负责建立连接,建立 TCP 连接或者 TLS 连接。 client.networkInterceptors :由开发者设置的圣夫龙,本质上和第两个圣夫龙类似,但是由于位置不同,所以用处也不同。 CallServerInterceptor :主要负责网络数据的允诺和积极响应,也就是前述的网络I/O操作。将允诺头与允诺体推送给伺服器,以及导出伺服器返回的 response。除了架构提供的圣夫龙外,OkHttp 支持用户自定义圣夫龙来对允诺做增强处置,自定义圣夫龙能分为两类,分别是应用领域程序圣夫龙和网络圣夫龙,他们发挥作用的层次结构如下表所示图:
图 2-3 圣夫龙(图片来自OkHttp官网)
不同的拦截器有不同的适用情景,他们各自的优缺点如下表所示:
应用领域程序圣夫龙
无需担心重定向和重试等中间积极响应。 总是被调用一次,即使 HTTP 积极响应是从缓存中提供的。 能观察到应用领域程序的原始允诺。不关心 OkHttp 注入的标头。 允许短路而不调用 Chain.proceed方法。 允许重试并多次调用 Chain.proceed方法。 能采用 withConnectTimeout、withReadTimeout、withWriteTimeout 调整呼叫超时。网络圣夫龙
能够对重定向和重试等中间积极响应进行操作。 缓存积极响应不会调用。 能观察到通过网络传输的原始数据。 能访问携带允诺的链接。2.5 职责链商业模式串联圣夫龙调用
OkHttp 内置了 5 个核心理念的圣夫龙用以完成允诺生命周期中的关键处置,同时它也支持加进自定义的圣夫龙来增强和扩展 Http 应用程序,这些圣夫龙通过职责链商业模式串联起来,使得的允诺能在不同圣夫龙之间流转和处置。
2.5.1 职责链商业模式
职责链商业模式 是一种行为结构设计商业模式, 允许将允诺沿着处置者链推送。 收到允诺后, 每个处置者均可对允诺进行处置, 或将其传递给链上的下两个处置者。
图 2-4 职责链(图片来自网络)
适用情景包括:
当程序需要采用不同方式处置不同种类的允诺时 当程序必须按顺序继续执行多个处置者时 当所需要的处置者及其顺序必须在运行时进行改变时优点:
能控制允诺处置的顺序 可对发动操作和继续执行操作的类进行解耦。 能在不更改现有标识符的情况下在程序中新增处置者。2.5.2 圣夫龙的串联
职责链的入口从第两个 RealInterceptorChain 对象的 proceed 方法调用开始。这个方法的结构设计非常巧妙,在完整的 proceed 方法里会做一些更为严谨的校验,去掉这些校验后该方法的核心标识符如下表所示:
publicResponse proceed( Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException { if(index >= interceptors.size) thrownewAsserti; // …… // Call the next interceptor in the chain. RealInterceptorChain next = newRealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index +1, request, call, eventListener, connectTimeout, readTimeout, writeTimeout); Interceptor interceptor = interceptors. get(index); Response response = interceptor.intercept(next); // …… returnresponse; }这段标识符能看成三个步骤:
索引判断。 index 初始值为0,它指示了圣夫龙对象在列表中的索引顺序,每执职责链串联
单独看这个方法似乎并不能将所有圣夫龙都串联起来,串联的关键是 intercept 方法,intercept 方法是实现 interceptor 接口时必须要实现的方法,该方法持有下两个职责链 对象 chain,在圣夫龙的实现类里只需要在 intercept 方法里的适当地方再次调用 chain.proceed 方法,程序指令便会重新回到以上标识符片段,于是就能触发对于下两个圣夫龙的查找和调用了,在这个过程中圣夫龙对象在列表中的先后顺序非常重要,因为圣夫龙的调用顺序就是其在列表中的索引顺序。
递归方法
从另两个角度来看,proceed 方法能看成是两个递归方法。递归方法的基本定义为“函数的定义中调用函数自身”,虽然 proceed 方法没有直接调用自身,但是除了最后两个圣夫龙以外,圣夫龙链中的其他圣夫龙都会在适当的位置调用 chain.proceed 方法,职责链对象和圣夫龙对象合在一起则组成了两个自己调用自己的逻辑循环。按照笔者个人理解,这也是为什么源标识符里 Chain 接口被结构设计成 Interceptor 接口的内部接口,在理解这段标识符的时候要把它们两个接口当成两个整体来看,从这样的角度看的话,这样的接口结构设计是符合“高内聚”的原则的。
圣夫龙 interceptor 和职责链 chain 的关系如下表所示图:
图 2-5 Interceptor 和 Chain 的关系图
三、OkHttp 圣夫龙在工程项目中的应用领域
在他们的工程项目中,有两类允诺需要在允诺头 Header 中加进认证信息,采用圣夫龙来实现能极大地简化标识符,提高标识符可读性和可维护性。核心理念标识符只需要实现符合业务需要的圣夫龙如下表所示:
加进允诺头的圣夫龙
publicclassEncryptInterceptorimplementsInterceptor{ @Override publicResponse intercept(Chain chain)throwsIOException { Request originRequest = chain.request; // 计算认证信息 String authorization = this.encrypt(originRequest); // 加进允诺头 Request request = originRequest.newBuilder .addHeader( “Authorization”, authorization) .build; // 向职责链后面传递 returnchain.proceed(request); } }之后在建立 OkHttpClient 应用程序的时候,采用 addInterceptor 方法将他们的圣夫龙注册成应用领域程序圣夫龙,即可实现自动地、无感地向允诺头中加进实时的认证信息的功能。
注册应用领域程序圣夫龙
OkHttpClient client = newOkHttpClient.Builder .addInterceptor( newEncryptInterceptor) .build;四、回顾总结
OkHttp 在 Java 和 Android 当今世界中被广为采用,通过采用 OkHttp 圣夫龙能解决两类难题——特别针对两类允诺标准化修正允诺或积极响应内容。深入细致了解 OkHttp 的结构设计和实现不仅能协助他们自学杰出开放源码应用软件的结构设计和代码实战经验,也有利于更快地采用应用软件优点以及对特定情景下难题的摸查。职责编辑试著从两个并行 GET 允诺的范例开始,首先通过源标识符片段概要预测了两个允诺发动过程中涉及的核心理念标识符,接著用时序的形式总结了允诺继续执行过程,然后用洼瓣展示了OkHttp的分层结构设计,如是说了各种圣夫龙的用途、工作层次及优缺点,之后着重预测了圣夫龙的职责链商业模式结构设计——本质是两个递归调用,最后用两个单纯的范比如是说了 OkHttp 圣夫龙在前述生产情景中的应用领域。
参考:
OkHttp官方文档 OkHttp源标识符导出系列文章END
十年磨一剑,开放源码中国新使命
这里有最新开放源码资讯、应用软件更新、技术干货等内容