这里主要解析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回调给用户。