本文使用okhttp3源码来讲解
1、同步和异步的区别
(1)同步方法execute()
okHttpBuilder.build().newCall()会创建一个RealCall对象
//OkHttpClient.java
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
然后看下RealCall的execute()方法
//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(); //执行请求
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this); //执行结束后从双向链表移除
}
}
(2)异步方法enqueue
异步方法enqueue也位于RealCall.java中,具体实现如下
//RealCall.java
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));//异步执行
}
创建了一个AsyncCall对象,并将回调接口作为参数。AsyncCall继承于抽象类NamedRunnable,NamedRunnable又继承自Runnable接口,所以这里新开了一个线程去执行execute()方法。
//NamedRunnable.java
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();//子线程执行
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
//RealCall.java
final class AsyncCall extends NamedRunnable { //子线程
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override protected void execute() { //继承自父类,并在子线程run方法中被调用
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();//具体执行任务
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));//结果回调
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response); //结果回调
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e); //结果回调
}
} finally {
client.dispatcher().finished(this);
}
}
}
看下client.dispatcher().enqueue做了啥
//Dispatcher.java
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
enqueue将任务添加到双端链表中,这里有两个队列-任务队列和等待队列,当并发任务数大于64或者相同域名数量大于5个时就加入到等待队列
2、拦截器种类和顺序
使用okhttp进行网络请求时不管是不同请求(execute())还是异步请求(enqueue(Callback responseCallback))都会走到getResponseWithInterceptorChain()方法来添加拦截器。
//RealCall.java
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)); //请求服务拦截器
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis()); //第5个参数index=0要注意,后面分析会用到
return chain.proceed(originalRequest);
}
根据代码可以看到拦截器添加的顺序依次为client.interceptors()、retryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、networkInterceptors、CallServerInterceptor,由于是ArrayList容器所以可以保证顺序。
看下拦截链的proceed方法,可以看到根据index参数以及RealInterceptorChain,每个拦截器都会执行其intercept方法,在intercept方法中会通过执行后续拦截链的proceed方法,这样就逐步执行了拦截连上的所有拦截器
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError(); //初始时index 是上面传入的第五个参数0
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); //从下个拦截器开始的拦截链,初始时由于index是0,则index+1等于1,相当于下一个拦截器的index就变为了1,一次类推index逐步增加
Interceptor interceptor = interceptors.get(index);//当前拦截器
Response response = interceptor.intercept(next);//以新的拦截链为参数,执行当前拦截器的intercept方法,这样就一次执行了拦截链上的每个拦截器
// 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;
}
网上盗个图说下拦截器流程