拦截器:Okhttp中提供的一种强大的机制,可以实现网络监听、请求/响应重写、请求失败重试等功能的实现(拦截器不区分异步/同步)
Okhttp不管是异步/同步,在RealCall.java
中都会执行Response result = getResponseWithInterceptorChain();
- 同步
RealCall.java
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();//执行该方法
.....省略无用代码
}
- 异步
RealCall.java
@Override public void enqueue(Callback responseCallback) {
...省略无用代码
client.dispatcher().enqueue(new AsyncCall(responseCallback));//跟到AsyncCall中
}
==============================分割线=========================
AsyncCall.execute();
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();//异步也是执行该方法
....省略无用代码
}
接下来看一下getResponseWithInterceptorChain()
具体做了什么操作,源码如下:
//方法字面意思:得到一个具有拦截器链的响应
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List 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));
//拦截器链
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//执行RealInterceptorChain.proceed();方法,下面将具体分析
return chain.proceed(originalRequest);
}
上面的getResponseWithInterceptorChain()
是通过RealInterceptorChain.proceed();
方法得到一个拦截器链,下面具体看一下proceed()
方法:
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.
// 在这里,得到了 next 下一个链,构造函数中将 index+1
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//interceptors 就是从构造函数中,得到的List
//也就是在RealCall.getResponseWithInterceptorChain();中添加的所有的拦截器
Interceptor interceptor = interceptors.get(index);
//在这里,执行拦截器的intercept();方法
//在具体拦截器的intercept()方法中,又会调用next chain的proceed();方法
//构成了一个链
Response response = interceptor.intercept(next);
....省略部分代码
return response;
}
proceed()
方法执行过程大概是:
在内部将index+1,得到下一个RealInterceptorChain
,通过具体的拦截器的intercept()
方法,继续执行下一个链的proceed();
方法,依次直到最后一个拦截器,从而形成一个链(有点类似于递归,依次往内部请求,结果从最内部一层一层传到最外层)。