在上一章的结尾我们遗留了一个很重要的方法
Response response = getResponseWithInterceptorChain();
该方法返回的是一个Response对象,相信使用过OkHttp的童鞋对于这个对象应该不陌生,这个就是Http网络请求最终的响应对象。那么getResponseWithInterceptorChain()是如何获取到响应对象的。在分析该方法前我们先来说一下OkHttp中的一个核心设计OkHttp拦截器。
拦截器是什么?
官网:拦截器是OkHttp中提供的一种强大机制,它可以实现网络监听、请求以及响应重写、请求失败重试等功能。
下面我们来看一下拦截器图。
OkHttp将拦截器分为两部分:
-
应用程序拦截器
这个拦截器是用户自己根据需求来实现的。 -
网络拦截器
这个是由源码提供的。总共有5个拦截器,见下图,具体的作用我们会在稍后进行讲解。
OkHttp实际上是构建了一个强大的拦截器链,将请求中的任务的各个部分进行拦截干预,达到灵活控制的目的,这是我个人的理解。
而拦截器的实现部分,以及真正的Http的请求以及响应部分都是由这个方法展开的。下面我们就来分析一下该方法,该方法位于源码RealCall类中
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//添加用户自己实现的<应用程序拦截器>
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) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
//使用List<Interceptor>拦截器集合构建RealInterceptorChain对象
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//调用Interceptor的proceed方法返回Response对象
return chain.proceed(originalRequest);
}
最终调用了
//调用Interceptor的proceed方法返回Response对象
return chain.proceed(originalRequest);
可以看到Interceptor.Chain是一个接口,那么该方法调用的就是RealInterceptorChain的proceed方法。接下来我们就看一下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;
this.connection = connection;
this.streamAllocation = streamAllocation;
this.httpCodec = httpCodec;
this.index = index;
this.request = request;
this.call = call;
this.eventListener = eventListener;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//interceptors就是之前创建的拦截器集合
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
代码量还算可以,这里我们来截取重要代码进行讲解
首先构造方法中
this.index = index;
然后proceed()方法中
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
之前我们在RealCall中的getResponseWithInterceptorChain()方法中通过构造函数创建了一个RealInterceptorChain对象,该对象将index赋值为int的默认值也就是0,然后调用了它的proceed(),而在它的proceed()的方法中又创建了一个新的RealInterceptorChain对象,而该对象使用的是index+1构建的,也就是说新创建的这个对象的index变量是上一个的+1,然后根据构造中的index值为下标,从interceptors拦截器集合中获取之前add进去的拦截器Interceptor对象,然后执行intercept(next)方法,传入新构建的RealInterceptorChain对象next。
设计精髓
通过index+1的方法赋值下一个构建出的RealInterceptorChain对象的index变量,然后从拦截器集合中不断寻找下一个拦截器,这样巧妙的方式,就构成了一个链条,也就是拦截器链,也是设计模式中的责任链模式。
下一篇文章我们就来分析下源码中的各个拦截器