目录
-
拦截器启动流程代码分析
拦截器的创建初始化以及启动过程,主要有3个步骤
- 创建拦截器集合;
- 创建串行职责链并放入拦截器集合以及初始索引;
- 启动串行拦截器;
具体的执行流程如下图
拦截器的主要逻辑在 RealCall.getResponseWithInterceptorChain()中
Response getResponseWithInterceptorChain() throws IOException {
// 1.创建拦截器集合
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
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));
// 2.创建串行职责链并放入拦截器集合以及初始索引
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
// 3. 启动串行拦截器
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
在上面的代码段中,我们可以看到拦截器的创建初始化以及启动过程,主要有3个步骤
- 创建拦截器集合;
在创建拦截器中会看到有几个比较重要的点,应用拦截器、默认拦截器、网络拦截器都会在这里装载;
装载应用拦截器
interceptors.addAll(client.interceptors());
装载默认拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
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));
-
创建串行职责链并放入拦截器集合以及初始索引;
在这里创建了一个串行职责链对象 RealInterceptorChain,并在构建中传入了拦截器集合 interceptors 和 index 为0的下标。
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
-
启动串行拦截器;
Response response = chain.proceed(originalRequest);
在这里我们看到chain已经开始执行了,我们在具体看下proceed方法
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
在这里可以看到真正的启动,通过index 获得Interceptor实例,并调用intercept方法,执行拦截逻辑。
-
拦截器怎么串行起来呢?
上文中,我们已经分析到拦截器的运行,调用Interceptor实例的intercept方法,那么关于拦截器如何串行起来,我们需要看一下intercept方法的实现。以 BridgeInterceptor 为例
public Response intercept(Chain chain) throws IOException {
// 业务逻辑 .....
Response networkResponse = chain.proceed(requestBuilder.build());
// .......
}
我们可以看到在intercept方法中又调用 chain的proceed方法,这里的调用又回到了上文的步骤3,而每个拦截器都会在完成业务逻辑后执行proceed,这样拦截器就串行起来了。这点官方的文档中也有提到
A call to chain.proceed(request) is a critical part of each interceptor’s implementation.
-
拦截器如何停下来
上文已经分析了拦截器如何开始,那么如何停下来的问题,关键还是在于proceed方法,最后一个拦截器不再调用proceed方法,那么拦截器也就停下来了。
那么如何保证最后一个拦截器不调用proceed,这点在 RealCall的 getResponseWithInterceptorChain方法中可以保证,因为拦截器是有序的,并且最后一个添加的是CallServerInterceptor,而这个拦截器并没有调用,所以 CallServerInterceptor可以保证拦截器一定可以停下来。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
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));
// ....
}