Java中的责任链模式
1.责任链模式又叫做职责链模式,赋予对象行为的设计模式,使多个参与者都有机会执行相应的逻辑,降低了耦合,平时开发过程中;我们其实已经接触到了责任链模式。只是是以另一种形态呈现:像switch、if-else,重构项目时对于这些首先想到的是责任链模式使结构更清晰,同样带来了一个问题。如果逻辑过于复杂,调用嵌套过深对性能是有一定的损失的。设计模式的多样化也表明了没有十全十美的设计模式。而我们需要掌握是思想。
2.责任链模式的UML图(网上爬的):
3.通过类图中可以明确的是,责任链模式包含了抽象的处理类Handler、客户端调用Client、具体的处理实现类ConcreteHandler。
4.以生活中职员请假为例子,在公司中通常请假是根据天数来确定审批的流程,三天、五天或者一个星期需要最终批准的上层是不一样的。
抽象的处理类Handler
1 | public abstract class Handler { |
TeamLeader处理类
1 | public class TeamLeader extends Handler { |
ProjectManager
1 | public class ProjectManager extends Handler { |
DepartmentManager
1 | public class DepartmentManager extends Handler { |
Client调用
1 | public class Client { |
打印信息:
1 | 第1次请假请假天数 = 3 |
OkHttp
1.对Java中的责任链首先有个意识,在看OkHttp中,开发请求网络框架,基本上都会接触OkHttp,其中就用到了责任链模式。具体看源码,就是想理解这种思想的运用,对比优秀的实现,在实际开发过程中或多或少会起到启发的作用。
2.OkHttpClient
相当于我们网络的配置控制中心,包括一些基础的配置,连接池、重试、桥接、协议等,主要配置:Dispatcher(线程调度)
设定了最大请求数,单个Host的最大请求数。Protocols
支持的协议,HTTP/1.1、HTTP/2
。ConnectionSpec
对于Socket的设置信息,明确是明文传输的HTTP,还是TLS的HTTPS。Interceptor
,核心链,包含了几个重要的拦截器。当然还包括其他的一些基础参数,不在赘述。
newCall
1.从实际运用的例子入手:
1 | private static void connectNet() { |
newCall(request)
方法返回的是一个RealCall
对象,实现了Call
的接口,当调用RealCall.execute()
时:
RealCall.getResponseWithInterceptorChain()会被调用,发起网络请求并拿到返回的响应值Response,同样的异步请求RealCall.enqueue()的调用也是大同小异的,主要区别在于Dispatcher的介入,通过线程池的调用将请求加入后台,实际上也是对getResponseWithInterceptorChain()的调用。另外不同的是,对于请求队列的维护是不同的(Dispatcher)中。
getResponseWithInterceptorChain(),计数核心方法,也是OkHttp责任链模式的核心方法,主要的工作就是将多个Interceptorr组装起来(List),创建一个RealInterceptorChain对象,而chain.proceed(request)一步步推荐链的执行,一步步分析。
Dispatcher
1.几个重要的参数:
1 | private int maxRequests = 64; |
2.定义了最大异步请求数为64,而单个Host最大的请求数为5,同时对于异步请求实现了两个双端队列来保存请求runningAsyncCalls、readyAsyncCalls
;这个很好理解,当我们的请求已经达到最大值64(或者Host为5),那么此时要是有新的请求过来当然是要将请求先保存起来。对于早期的处理逻辑,当有请求过来时,先判断是否达到请求阀值。决定将请求放入哪个队列当中,在新版本中这个逻辑已经被修改了。同样的对于同步请求是直接入队列runningSyncCalls
。
1 | //早期的异步请求入队列操作 |
3.同步方法的调用,getResponseWithInterceptorChain,直接请求返回Response。
1 | public Response execute() throws IOException { |
异步请求关键类-AsyncCall
1.当我们发起异步请求时:
1 | client.newCall(request).enqueue(); |
关键方法-getResponseWithInterceptorChain()
1.RealCall#getResponseWithInterceptorChain()
1 | Response getResponseWithInterceptorChain() throws IOException { |
2.我们的Response经过核心方法getResponseWithInterceptorChain()的包装,最终拿到了想要的结果,这里是OkHttp责任链模式的核心,设计的很巧妙。看看具体做了哪些操作。
RetryAndFollowUpInterceptor
1.拦截器都实现了统一的接口Interceptor,看其中的关键方法:
1 | //定义了默认最大重试次数20次 |
2.(RealInterceptorChain)关键方法proceed
,之前已经了解,在RealCall是整个链开始传递的起点:
1 | //RealCall,可以看到index为0,我们所有的拦截都被保存在list集合之中,可以发现后序的取interceptor都是基于这个index自增来获取。 |
ConnectInterceptor
1.主要就是与服务器建立链接TCP链接或TCP-TLS链接,这个比较特殊,之前提到拦截的前序操作基于调用方法realChain.proceed();
之前,但是这个是没有后序
操作的:
1 | /** Opens a connection to the target server and proceeds to the next interceptor. */ |
CallServerInterceptor
1 | /** This is the last interceptor in the chain. It makes a network call to the server. */ |
1.责任链尾,实质的请求与I/O操作,将请求数据写入Socket中,并从Socket读取响应数据(TCP/TCP-TLS对应的端口)。对于I/O
的操作是基于Okio
,OkHttp
的高效请求同样离不开Okio
的支持,这里先不细说。整理整个流程图就是:
Tip
1.OkHttp
作为优秀的Android
网络请求框架,是很值得深入研究的,这里主要对整个流程做一下梳理,具体的实现细节同样需要花大量的时间整理。对全局的把握有助于整个实现思路做到心中有数。