ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

03、Android--OkHttp原理解析

2021-06-29 01:33:59  阅读:181  来源: 互联网

标签:03 拦截器 请求 -- interceptors call OkHttp new RealCall


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

标签:03,拦截器,请求,--,interceptors,call,OkHttp,new,RealCall
来源: https://www.cnblogs.com/pengjingya/p/14948157.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有