OkHttp源码看一看,了解一下思路

OkHttp使用过程中基本上分为三步:

            //1.创建一个OkHttpClient对象
            OkHttpClient client = new OkHttpClient();

            //2.创建一个请求
            Request request = new Request.Builder()
                    .url(url)
                    .get().build();

            //3.先把Request封装成一个Call对象,然后执行请求
            Response response = client.newCall(request).execute();

下面就根据这三步来看看源码,了解一下思路。具体细节就不去细看了:


1.创建一个OkHttpClient对象

  //调度器。主要作用是通过双端队列保存Calls(同步&异步Call),同时在线程池中执行异步请求
  final Dispatcher dispatcher;

  //应用拦截器的List
  final List<Interceptor> interceptors;

  // 网络拦截器的List
  final List<Interceptor> networkInterceptors;

  //使用Builder模式构造一个OkHttpClient实例
  public OkHttpClient() {
    this(new Builder());
  }

其实在构造过程中没啥好看的,就是使用Builder模式构造一个实例呗,只是会默认设置一下里面的变量。
这些变量中最重要的就是那三个,已经标出来了。

2.构造一个Request

public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final @Nullable RequestBody body;
  final Map<Class<?>, Object> tags;
  }

其实这个类没啥好说的,主要就是里面的一些变量。比如请求的Url,请求方法 method, 请求头 headers, 请求体body等。
相应的,有Request 那就必须得有 Response , 也没啥,里面也有一些变量,大致上都差不多,具体细节不用追究。

3.构造一个Call对象

也就是调用了 OkHttpClient#newCall 方法:

  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

好吧,看看 RealCall#newRealCall 方法:

  /**
   * 将网络请求Request封装成一个RealCall对象
   */
  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }

好吧,就是创建一个RealCall对象而已。
好像到现在都没看到啥实质内容啊。
接下来才是重点。

4.1 对于同步,执行execute 方法

也就是执行RealCall#execute 方法:

  /**
   * 同步请求执行
   */
  @Override public Response execute() throws IOException {

    //executed如果是true,就说明已经被执行过了。在此调用就会抛出错误。一个Call只能被调用一次
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }

    //追踪栈信息,不用管
    captureCallStackTrace();
    eventListener.callStart(this);

    //最关键的部分,将请求交给 Dispatcher 去处理。
    try {
      client.dispatcher().executed(this);

      //调用各种拦截器。
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }

好了,真正的核心就两句

client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();

首先看看第一句,这个client.dispatcher()其实返回的就是一个 Dispatcher 对象,该类中主要有以下几个重要的变量:

  //线程池(核心线程为0,非核心线程为无限)
  private @Nullable ExecutorService executorService;

  //异步请求的双向队列。当单个Host并发超过5个后,Call对象就放入该队列中。
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  //异步请求的双向队列,当前正在执行的Call
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  //同步请求放入该双向队列中
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

而execute 方法就这么一句话:

  /**
   * 执行同步请求。直接把Call添加到正在执行请求的双向队列中
   */
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

所以实在没看出啥来。

好吧,接下来我们看看第二句:
Response result = 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));

    //创建一个拦截器链类。RealInterceptorChain是实现了Interceptor.Chain接口的类
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    //把Chain 传递到下一个拦截器中
    return chain.proceed(originalRequest);
  }

这个方法就是添加各种拦截器,然后执行拦截器的 proceed 方法。那就看看 RealInterceptorChain#proceed 方法:

  /**
   * 执行拦截器链类该方法,获取到Response对象
   */
  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }


  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {

    //这里说明拦截器已经没了,拦截器的数量就是interceptors.size()。
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    //又新建了一个 RealInterceptorChain。可以看到了index+1,实际上这个就是用来控制遍历interceptors列表的。
    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);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }

可以看到,其核心思想就是去遍历 interceptors(一个List)的所有元素,然后调用每个拦截器的 intercept 方法,可以看到传入的参数是下一个拦截器的Chain.
这里有点疑问?为啥调用了intercept 方法就可以遍历整个interceptors列表呢?
这是因为每个拦截器的 intercept 方法内部都都有这么一句(最后一个拦截器除外):

chain.proceed(request)
这就是一个循环调用,循环的终止条件就是index >= interceptors.size()。

总结:
对于同步请求,主要步骤如下:

  1. 调用 RealCall#execute 方法。
  2. 调用 Dispatcher#executed 方法,作用就是将call 加入的 runningAsyncCalls队列中
  3. 调用 RealCall#getResponseWithInterceptorChain,用于设置各种拦截器,然后并执行拦截器的 intercept 方法,并返回一个Response对象
  4. 调用 Dispatcher#finished 方法,传入的第三个参数为false, 即不执行 promoteCalls方法,到此结束。

对于拦截器的链式调用如下:

  1. 执行 RealCall#getResponseWithInterceptorChain 方法,创建一个拦截器的列表interceptors,然后创建一个Chain, 执行Chian#proceed方法
  2. 在 RealInterceptorChain#proceed 方法中,在创建一个Chain, 然后根据索引取出interceptors里面的一个拦截器,调用 Interceptor#intercept 方法,并把新建作为参数传入到拦截器里
  3. Interceptor#intercept 方法里,执行完各自的需求的额步骤后,在调用Chian#proceed方法,最后一个拦截器不需要执行。

4.2 对于异步的,调用enqueue方法

也就是直接调用了 RealCall#enqueue 方法。

  /**
   * 异步执行请求
   */
  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }

    //用来追踪栈的信息,不用管,不影响。
    captureCallStackTrace();
    eventListener.callStart(this);

    //AsyncCall 实际上就是一个Runable的实现类
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

好吧,直接转到了Dispatcher#enqueue 方法,

  /**
   * 执行异步请求
   */
  synchronized void enqueue(AsyncCall call) {
    //判断当前正在执行的请求总数是否小于64,并且单个Host正在执行的请求小于5
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      //满足条件,放入runningAsyncCalls,并使用线程池执行该Call
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      //不满足条件,放入readyAsyncCalls中
      readyAsyncCalls.add(call);
    }
  }

可以看到,如果当前可以执行,就放入到runningAsyncCalls,然后通过线程池执行该请求。不能够立即执行的,就放入等待队列中(即readyAsyncCalls)。
对于 executorService().execute(call),这个call 实际上市RealCall的内部类AsyncCall,这个AsyncCall实际上是一个间接实现了Runnable的类,所以直接看 AsyncCall#execute方法:

    @Override protected void execute() {
      boolean signalledCallback = false;
      try {

        //拦截器链
        Response response = getResponseWithInterceptorChain();

        if (retryAndFollowUpInterceptor.isCanceled()) {
          //重试失败,调用onFailure方法抛出错误
          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 {
        //结束,调用Dispatcher#finished 方法
        client.dispatcher().finished(this);
      }
    }
  }

可以看到,getResponseWithInterceptorChain 方法,之前同步的时候已经说过了。所以已经知道了怎么执行异步请求了。
还有一点finally 代码快中执行了Dispatcher#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!");

      //上一个请求执行完成后,调用 promoteCalls 来循环执行下一个请求
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

  /**
   * 遍历正在等待执行的Call(即readyAsyncCalls双向队列中的Call)
   */
  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();

      //同一个Host的请求不足5个,满足条件
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        //将Call对象从readyAsyncCalls队列中移除并添加到runningAsyncCalls,然后执行该Call
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      //遍历过程中,只要 runningAsyncCalls 达到了了最大值,就停止
      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

ok, 可以看到了,基本思想就是把readyAsyncCalls的元素拿到runningAsyncCalls并放在线程池中执行。

对于异步的总结如下:

  1. 执行 RealCall#enqueue 方法
  2. 执行 Dispatcher#enqueue 方法。如果当前runningAsyncCalls队列可以放入元素,就直接add,然后调用线程池执行ExecutorService().execute(call)。否则就放入readyAsyncCalls队列中,等待执行.
  3. 在线程池中的call,实际上是间接实现了Runnable接口的AsyncCall类,执行execute 方法。
  4. AsyncCall#execute 中,先调用getResponseWithInterceptorChain返回Response对象,这里一个call就执行完成了。最后调用 Dispatcher#finished方法。
  5. 在Dispatcher#finished调用了 Dispatcher#promoteCalls方法,该方法就是将 call 从 readyAsyncCalls 中取出放到 runningAsyncCalls 中并使用线程池执行该call。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值