使用OkHttp进行请求,我们首先需要构建一个Request对象,可以看到这里使用建造者模式创建了一个Request对象,之后再传入request,生成Call对象。
Request request = new Request.Builder()
.url("http://xxx/yyy")
.method("GET", null)
.build();
OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
获得Call对象后,可以调用enqueue
进行异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
也可以通过调用execute
进行同步请求
Response response = call.execute();
总之,无论是调用enqueue
还是execute
,都会调用Dispatcher来执行。
下面以enqueue
为例,会调用到RealCall.enqueue
public void enqueue(Callback responseCallback) {
enqueue(responseCallback, false);
}
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
这里的client.dispatcher()
就是一个Dispatcher对象,Dispatcher是个任务调度类,主要用作控制并发的请求,Dispatcher有几个重要的属性,我们先来看一下
//最大并发请求数
private int maxRequests = 64;
//每个主机的最大请求数
private int maxRequestsPerHost = 5;
//消费者线程池
private ExecutorService executorService;
//将要运行的异步请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在运行的异步请求队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在运行的同步请求队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
//主机最大请求数
private int maxRequestsPerHost = 5;
再来看Dispatcher.enqueue
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.host().equals(call.host())) result++;
}
return result;
}
可以看到,如果正在运行的异步请求队列小于最大请求数,并且每个主机的请求数小于主机最大请求数,那么会将这个AsyncCall加入到runningsAsyncCalls队列中,并会调用executorService()
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
通过executorService()
,会获得线程池,将这个AsyncCall通过线程池立即执行。
否则,会将AsyncCall加入到readyAsyncCalls队列,等待执行。
再来看下AsyncCall这个类,这个类在上面RealCall.enqueue
中,会进行创建
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
可以看到,它在构造方法中传入了responseCallback,这个也就是我们调用Call.enqueue
时候传入的回调。
主要来看AsyncCall.execute
,线程池在执行时会调用这个方法。
protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
//...
responseCallback.onFailure(RealCall.this, e);
} finally {
client.dispatcher().finished(this);
}
}
首先,会调用getResponseWithInterceptorChain()
来获得Response对象,getResponseWithInterceptorChain()
也就是真正执行请求的地方。
之后,会根据结果调用responseCallback.onFailure
或者responseCallback.onResponse
。
但最终,无论是否请求成果,都会调用client.dispatcher().finished()
,client.dispatcher()
我们已经很熟悉了多好就是DIspatcher对象。
synchronized void finished(AsyncCall call) {
if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
promoteCalls();
}
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
可以看到,这里首先把这个AsyncCall从runningAsyncCalls中移除,并在promoteCalls
的时候,从readyAsyncCalls中取出下一个AsyncCall,并加入到runningAsyncCalls队列并通过调用线程池执行。
runningAsyncCalls.add(call);
executorService().execute(call);
总结
OkHttp的请求流程,主要步骤如下
1. 通过建造者模式构建出Request对象
2. 传入Request对象构建出Call对象
3. 通过Call.enqueue或Call.execute来进行异步或同步的请求
Call的内部请求流程,主要步骤如下
1. 传入请求回调responseCallback生成AsyncCall对象
2. 通过Dispatcher.enqueue()
,传入AsyncCall
3. 如果符合请求数和主机请求数,则将AsyncCall加入到runningAsyncCalls正在运行的异步请求队列,并通过线程池执行AsyncCall
4. 否则,将AsyncCall加入到readyAsyncCalls将要运行的异步请求队列 ,等待执行
5. 通过AsyncCall.getResponseWithInterceptorChain()
执行真正的请求,并进行相应的回调
6. 调用Dispatcher.finished()
,将AsyncC从runningAsyncCalls队列中移除,并将下一个AsyncCall从readyAsyncCalls中获取,加入到runningAsyncCalls队列中,并通过线程池执行。
至此,OkHttp的请求流程的源码就已经解析完了。下篇文章我们将分析下OkHttp的拦截器。
源码分析中的OkHttp版本为com.squareup.okhttp3:okhttp:3.2.0