03、Android--OkHttp原理解析

OkHttp原理

这里主要解析OkHttp请求网络流程和复用连接池。

OkHttp请求网络流程

整体的结构图如下所示:

03、Android--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回调给用户。

上一篇:MonoDistill 阅读笔记 ICLR2022


下一篇:axios Interceptors(拦截器) Cancellation(取消发送)