OkHttp原理
这里主要解析OkHttp请求网络流程和复用连接池。
OkHttp请求网络流程
整体的结构图如下所示:
(1)从请求处理开始分析
当我们要请求网络的时候需要用OkHttpClient.newCall(request)进行execute或者enqueue操作;当调用newCall方法时,会调用如下代码:
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
我们调用enqueue异步请求网络实际上是调用了RealCall的enqueue方 法。查看newRealCall方法如下:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call; // 返回RealCall对象
}
从代码中可以看出,我们调用的enqueue方法其实是调用RealCall的enqueue方法:
@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 RealCall.AsyncCall(responseCallback));
}
可以看到最终的请求是dispatcher来完成的,接下来就开始分析dispatcher。
(2)Dispatcher任务调度
Dispatcher主要用于控制并发的请求,它主要维护了以下变量:
public final class Dispatcher {
/** 最大并发请求数 */
private int maxRequests = 64;
/** 每个主机最大请求数 */
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
/** 消费者线程池 */
private @Nullable ExecutorService executorService;
/** 将要运行的异步请求队列 */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** 正在运行的异步请求队列 */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** 正在运行的同步请求队列 */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
......
}
接下来看看Dispatcher的构造方法,如下所示:
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
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;
}
Dispatcher有两个构造方法,可以使用自己设定的线程池。如果没有设定线程池,则会在请求网络前自己创建默认线程池。
当调用 RealCall 的 enqueue 方法时,实际上是调用了 Dispatcher的enqueue方法,它的代码如下所示:
synchronized void enqueue(RealCall.AsyncCall call) {
// 当正在运行的异步请求队列中的数量小于64并且正在运行的请求主机数小于5时
// 把请求加载到 runningAsyncCalls中并在线程池中执行,否则就加入到
// readyAsyncCalls中进行缓存等待。
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
线程池中传进来的参数是AsyncCall,它是RealCall的内部类,其内部也实现了execute方法,如下所示
@Override
protected void execute() {
boolean signalledCallback = false;
try {
// 返回了Response,很明显这是在请求网络
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);
}
}
finished方法如下所示:
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
// 重点标记
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
finished方法将此次请求从runningAsyncCalls移除后还执行了promoteCalls方法:
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
// 从readyAsyncCalls取出下一个请求,加入runningAsyncCalls中并交由线程池处理。
for (Iterator<RealCall.AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
RealCall.AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
从readyAsyncCalls取出下一个请求,加入runningAsyncCalls中并交由线程池处理。
(3)Interceptor拦截器
接下来在RealCall的executor方法里查看getResponseWithInterceptorChain方法,如下所示:
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());
return chain.proceed(originalRequest);
}
创建了一个拦截器队列 interceptors
,然后将 interceptors
通过 RealInterceptorChain
类的实例对象来进行处理。接下来看看RealInterceptorChain的proceed方法:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
......
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
// 从拦截器列表中取出拦截器
Interceptor interceptor = interceptors.get(index);
// 调用intercept进行拦截操作
Response response = interceptor.intercept(next);
......
return response;
}
其中proceed方法主要作用就是依次取出拦截器链表中的每个拦截器去获取Response。
这些拦截器包括:
用户自定义的拦截器
retryAndFollowUpInterceptor:重试和重定向拦截器,主要负责网络失败重连。
BridgeInterceptor:主要负责添加交易请求头。
CacheInterceptor:缓存拦截器,主要负责拦截缓存。
ConnectInterceptor:网络连接拦截器,主要负责正式开启http请求。
CallServerInterceptor:负责发送网络请求和读取网络响应。
总结:OKHttp中的一个网络请求其实就是5个拦截器依次执行自己的intercept方法的过程
在拦截器链中执行的结果,在同步请求中会直接在response返回,异步请求:
final class RealCall implements Call {
...
final class AsyncCall extends NamedRunnable {
...
@Override
public Response execute() throws IOException {
...
responseCallback.onResponse(RealCall.this, response);
...
}
...
异步请求时会把拦截器链的处理结果通过Callback的onReponse回调给用户。