1.引言
我们在前面几个章节的学习过程中,已经可以明白OkHttp的基本使用,OkHttp在使用的过程中几个常用的类的分析,OkHttp的分配器Dispatcher。其中在RealCall中,不管是同步请求还是异步请求,最终都会调用的一个方法,得到网络请求响应结果Response,就是getResponseWithInterceptorChain()方法。因为这个方法用的是拦截器链调用拦截器执行对应的方法,所以我们决定放到现在来讲,我们先看一下getResponseWithInterceptorChain()的调用位置:
//同步请求获取请求结果
@Override public Response execute() throws IOException {
...
try {
...
Response result = getResponseWithInterceptorChain();//获取请求结果
...
return result;
} catch (IOException e) {
...
} finally {
...
}
}
上面我们看到的,是我们调用Call的同步请求方法execute()时,的部分代码,可以看到,在该方法中真正获取请求结果的只有一句代码Response result = getResponseWithInterceptorChain(),就是说,同步请求会直接调用getResponseWithInterceptorChain()方法,获取Response并返回个调用者。
我们再看异步请求是如何调用的getResponseWithInterceptorChain()方法,首先我们异步请求调用的是Call的enqueue(Callback)方法:
//Call的异步请求方法,请求结果会利用Callback接口回调返回给调用者
@Override public void enqueue(Callback responseCallback) {
...
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
通过部分代码,我们看到,Call的enqueue(Callback)方法,会调用Dispatcher的enqueue(AsyncCall)方法,我们继续看一下Dispatcher的enqueue(AsyncCall)方法:
//Dispatcher的异步请求方法,被Call调用。Asyncall是异步请求任务
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);//线程池执行异步任务,最终会执行AsyncCall的execute()方法
} else {
readyAsyncCalls.add(call);
}
}
上面的代码我们前面已经讲过多次,executorService().execute(call)使用线程池异步执行了异步请求任务,其中的请求任务代码,在AsyncCall类的execute()方法中,相当于在异步线程中执行了AsyncCall类的execute()方法,所以我们在跳转到AsyncCall类中,查看一下它的execute()方法:
//RealCall的内部类AsyncCall,用来做异步请求任务,是Runnable的子类。
@Override protected void execute() {
...
try {
//获取请求结果
Response response = getResponseWithInterceptorChain();
if (...) {
...//判断,使用Callback接口回调返回给调用者
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
...//判断,使用Callback接口回调返回给调用者
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
...
} else {
...//判断,使用Callback接口回调返回给调用者
responseCallback.onFailure(RealCall.this, e);
}
} finally {
...
}
}
上面代码,相信大家都能看懂,在AsyncCall的execute()方法中调用了getResponseWithInterceptorChain()方法。获取到了请求结果,然后经过判断,在利用调用者传进来的Callback接口,做接口回调,将结果回传给调用者,完成了异步请求。
2.getResponseWithInterceptorChain()方法
前面说了这么多,就是为了说明不管是同步请求还是异步请求,都会调用RealCall中的getResponseWithInterceptorChain()来获取请求结果Response,所以我们现在将getResponseWithInterceptorChain()代码放上来,分析一下:
//RealCall的同步、异步请求都会调用此方法,这是获取网络请求结果Response的关键方法
Response getResponseWithInterceptorChain() throws IOException {
//创建一个存储拦截器的集合
List<Interceptor> interceptors = new ArrayList<>();
//将用户传入的Application拦截器添加到集合中
interceptors.addAll(client.interceptors());
//将重定向拦截器添加到集合中
interceptors.add(retryAndFollowUpInterceptor);
//将桥接拦截器加入到集合中
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//将缓存拦截器加入到集合中
interceptors.add(new CacheInterceptor(client.internalCache()));
//将连接拦截器加入到集合中
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {//如果不是WebSocket连接
//将用户传入的Network拦截器加入的
interceptors.addAll(client.networkInterceptors());
}
//将CallServer拦截器(与服务器进行数据交互)加入到集合中
interceptors.add(new CallServerInterceptor(forWebSocket));
//创建拦截器链,index初始值为0
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//调用拦截器链的proceed方法,就会调用到所有拦截器,并返回请求结果Response
return chain.proceed(originalRequest);
}
这一节,我们先不讲代码中提到的每个拦截器的作用,我们只讲拦截器的调用。我们从上面代码中可以看到,首先会将各种拦截器按照先后顺序,分别加入到新创建的ArryList集合中,然后创建了Interceptor.Chain拦截器链实例,在创建过程中,构造函数传入了存有各种拦截器的集合interceptors、数字0、用户创建好的Request对象、当前RealCall对象、OkHttp网络请求详细事件回调接口、超时设置。最后,调用了拦截器链chain的proceed(Request)方法,该方法返回Response正是调用者需要的服务器端的响应结果。我们先大概知道一下,这个方法中,主要做了些什么工作。接下来我们来看拦截器链。
3.Interceptor.Chain,拦截器链
首先我们通过代码查找,看到Interceptor.Chain是一个interface,它的目前唯一实现类就是RealInterceptorChain,我们看下这个类的构造方法
//RealInterceptorChain构造方法
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
this.interceptors = interceptors;//RealCall那边创建好并且已经添加好了所有拦截器
this.connection = connection;//null
this.streamAllocation = streamAllocation;//null
this.httpCodec = httpCodec;//null
this.index = index;//RealCall传入的是0
this.request = request;//用户构建好的Request
this.call = call;//当前RealCall
this.eventListener = eventListener;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
我们需要注意一点,他的变量index正是我们刚才RealCall的getResponseWithInterceptorChain()方法中传入的0,我们接着看一下我们前面调用的RealInterceptorChain的proceed(Request)方法:
//首次调用拦截器链
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
//继续调用拦截器链,将获取到的Response返回去
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
...
//这里需要注意,创建的拦截器链RealInterceptorChain,传入的参数中(index+1)
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//这里需要注意,获取到的拦截器是角标为index的拦截器,而index正是通过其构造函数赋值的
Interceptor interceptor = interceptors.get(index);
//调用拦截器的intercept()方法获取Response
Response response = interceptor.intercept(next);
...
return response;//将请求结果返回
}
讲到这里,可能很多人还是有些懵懵懂懂,我来帮大家捋一下:
1、在RealCall的getResponseWithInterceptorChain()方法中,我们第一次创建了拦截器链对象RealInterceptorChain,将存有拦截器的集合interceptors传给了RealInterceptorChain,同时设置了它的index为0,紧接着调用了RealInterceptorChain的proceed方法;
2、在RealInterceptorChain的proceed方法中,再次创建了RealInterceptorChain的实例,继续将存有拦截器的集合interceptors传递给新创建的RealInterceptorChain,这时给他设置的index为当前index+1,然后从interceptors中获取角标为当前index的Interceptor,执行Interceptor的intercept(Chain)方法,参数Chain就是新创建的index+1的RealInterceptorChain对象,并将获取到的Response返回给上一个调用者;
3、Interceptor本身是interface,其intercept(Chain)方法具体看它的实现类,可以肯定的一点是,intercept(Chain)方法中,除了做拦截器本身该做的一些操作外,会继续调用Chain的proceed方法,进入Chain的proceed方法中继续创建index+1的Chain,并且获取角标为index的Interceptor,调用它的intercept(Chain)方法......一直调用下去,直到最后一个拦截器为止。
上面我说捋一下,我想还有人不太明白,因为到现在为止,还缺少一部分代码,那就是Interceptor的intercept(Chain)方法究竟是怎么样子的,我们先看下Interceptor接口的类继承情况
其中LoggingInterceptor是我自己创建的继承自Interceptor,其他五个都是OkHttp框架已经提供的拦截器,我们在刚才讲getResponseWithInterceptorChain()方法时候,都见过的,先不纠结每一个拦截器的作用。我们主要是为了研究一下这些拦截器的intercept(Chain)方法。getResponseWithInterceptorChain()方法创建了存储拦截器的ArrayList集合,并且将拦截器都存入了该集合,我们刚才提到,会根据顺序,每次index+1来获取interceptors中的Interceptor,并调用其intercept(Chain)方法。我们取两个具有代表性的进行研究,这五个拦截器中,按照添加顺序排在最前面的RetryAndFollowUpInterceptor和排在最后的CallServerInterceptor,分别看一下他们的intercept(Chain)方法
RetryAndFollowUpInterceptor的intercept(Chain)方法
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
...
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
...
while (true) {
...//此处调用了拦截器链RealInterceptorChain的proceed方法
response = realChain.proceed(request, streamAllocation, null, null);
...
return response;
...
}
}
我们可以发现,在RetryAndFollowUpInterceptor的intercept(Chain)方法中,的确调用了拦截器链RealInterceptorChain的proceed()方法,这样就可以继续往下,调用下一个Interceptor的intercept(Chain)方法,一直调用下去,直到最后一个拦截器CallServerInterceptor结束。
CallServerInterceptor的intercept(Chain)
//这是CallServerInterceptor的intercept(Chain)方法,该方法不会调用Chain的proceed方法
@Override public Response intercept(Chain chain) throws IOException {
...
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
...
return response;
}
通过仔细阅读该代码,发现CallServerInterceptor果然没有继续调用Chain的proceed方法。拦截器链Chain的proceed方法,第一次调用,是被RealCall类的getResponseWithInterceptorChain()方法,然后proceed获取角标为index的Interceptor,调用Interceptor的intercept(Chain)方法,index+1,intercept(Chain)方法继续调用下一个RealInterceptorChain的proceed方法,一直这样调用下去,直到最后一个拦截器,这就是拦截器链的调用。
4.总结
我们先通过两幅幅图来描述拦截器链的工作
我们来简单的总结一下本章要跟大家分享的:
1、OkHttp的网络请求,其本质上是由拦截器链的调用完成的;
2、拦截器链的调用,起始于RealCall的getResponseWithInterceptorChain方法,结束与最后一个拦截器CallServerInterceptor的intercept(Chain)方法;
3、连接器链的调用,RealInterceptorChain的作用是按照顺序依次调用每一个拦截器的intercept(Chain)方法。拦截器Interceptor的作用是发挥自身拦截器的特性,对Request和Response做出操作,调用RealInterceptorChain的proceed()方法,让其继续下去;
4、我们可以将拦截器的调用看作递归,逐层向下调用,直到最后一个拦截器返回Response,然后在逐层向上,一边处理Response一边返回给上一层,最终返回给调用。
本章节关于拦截器链的讲解到此结束了,拦截器是OkHttp框架的精髓,所以我们会拿出几篇文章来详细分析,下一章节开始我们将分析每一个拦截器。