okhttp源码解析(一) 请求流程分析

前言

okhttp是我们安卓中运用最多的网络请求框架了,它的优势有很多,如支持HTTP2,SPDY,GZIP压缩,复用连接池提升效率等。

  • 1.简单使用
//异步请求
            OkHttpClient okHttpClient = new OkHttpClient();
            Request request = new Request.Builder().url("https://www.baidu.com").build();
            okHttpClient.newCall(request1).enqueue(new Callback() {
              @Override
             public void onFailure(Call call, IOException e) {}
              @Override
             public void onResponse(Call call, Response response) throws IOException {}
             });
//同步
            OkHttpClient okHttpClient = new OkHttpClient();
            Request request = new Request.Builder().url("https://www.baidu.com").build();
                try {
                    Response response = okHttpClient.newCall(request).execute();
                } catch (IOException e) {
                    e.printStackTrace();
                }

  • 2.OkHttpClient 分析
 public OkHttpClient() {
    this(new Builder());
  }

public static final class Builder {
    Dispatcher dispatcher;
    @Nullable Proxy proxy;
    List protocols;
    List connectionSpecs;
    final List interceptors = new ArrayList<>();
    final List networkInterceptors = new ArrayList<>();
    EventListener.Factory eventListenerFactory;
    ProxySelector proxySelector;
    CookieJar cookieJar;
    @Nullable Cache cache;
    省略若干.....

  • okhttpClient里有个静态内部类Builder,这里运用了Builder设计模式同步builder动态构建出一些常用的参数,如我们常见的connectTimeout,readTimeout,writeTimeout,Cache,我们自定义的拦截器等。
/**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
  • newCall 方法是其中最重要的一个方法,通过我们传入的request来发起请求的。

  • RealCall是Call的实现类,方法里通过newRealCall方法把okhttpclient和request传了过去,返回了一个RealCall对象,然后我们通过该对象来发起同步或异步请求。

  • 3.Dispatcher分析
  • 上面我们收到RealCall 是用来发起请求的,发起请求就不得不提到一个类Dispatcher

  • 这个类是在我们构建OkhttpClient的时候初始化的,是okhttpclient的成员

  • 这个类用来管理所有同步或异步请求的,它还有发起异步请求的功能

  //用来处理异步请求的线程池
  private @Nullable ExecutorService executorService;
  //待请求的异步任务队列
  private final Deque readyAsyncCalls = new ArrayDeque<>();
 // 正在请求的异步任务队列
  private final Deque runningAsyncCalls = new ArrayDeque<>();
  //正在请求的同步任务队列
  private final Deque runningSyncCalls = new ArrayDeque<>();
......
//SynchronousQueue是一个内部只能包含一个元素的队列。插入元素到队列的线程被阻塞,直到另一个线程从队列中获取了队列中存储的元素。同样,如果线程尝试获取元素并且当前不存在任何元素,则该线程将被阻塞,直到线程将元素插入队列。
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
  • 这里用到的线程池核心线程为0,非核心线程数量为无限,闲置时间为60s
  //同步
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }
  //异步
  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

  • Dispatcher中有二个重要的方法,其中executed方法比较简单是直接把传入的请求加到同步队列中

  • enqueue方法会判断正在执行的请求是否小于64并且同一个host的请求是否小于5,这里传入的AsyncCall 实则为一个Runnable对象,满足条件就把它加入到请求队列并调用线程池执行它

  • 否则就把它加入到等待队列中

  • 4.RealCall 分析
  • 上面我们收到RealCall 是用来发起请求的,它发起请求主要有如下二个方法

//同步
  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    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);
    }
  }

//异步
 @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 AsyncCall(responseCallback));
  }

  • execute方法调用我们上面提到的dispatcher的executed方法,把call加到同步队列
  • 执行getResponseWithInterceptorChain()来获取Response
  • enqueue也是调用的dispatcher执行的enqueue方法
  • 上面我们分析的enqueue方法,AsyncCall是一个Runnable由dispatcher里面的线程池执行它
final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        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);
          LogUtils.LogE("onFailure2");
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }
  • 可以看到里面的execute的方法最终也是调用了RealCall方法里面的getResponseWithInterceptorChain()方法来得到Response,所以getResponseWithInterceptorChain是最终执行请求得到response的方法
private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }
  • 这里简要说下client.dispatcher().finished(this)这个方法,它执行的是dispatcher里面的finished方法,它会把执行完成的call从正在请求的队列中移除并且会执行promoteCalls方法把readyAsyncCalls等待的异步请求中移动到runningAsyncCalls,并且调用线程池执行它
  • 这样就保证了异步的请求有序的进行
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List 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);
  }

  • 这里就是okhttp最核心的地方了,首先创建了一个Interceptor的集合

  • Interceptor就是拦截器的意思,这里主要有retryAndFollowUpInterceptor,BridgeInterceptor,CacheInterceptor,ConnectInterceptor,CallServerInterceptor五个主要的拦截器

  • retryAndFollowUpInterceptor负责断线重连

  • BridgeInterceptor负责请求头的一些参数构建以及gzip压缩处理

  • CacheInterceptor负责okhttp缓存相关的操作

  • ConnectInterceptor负责建立socket链路连接,里面定义了连接池复用连接等

  • CallServerInterceptor负责发送请求获取响应

  • RealInterceptorChain是用来串联这些拦截器让它们各司其职,调用proceed方法完成请求

  • 5.RealInterceptorChain分析
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

....省略若干代码
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
.....省略若干代码
    return response;
  }
  • 可以看到proceed方法中又创建了一个RealInterceptorChain把interceptors集合以及 index + 1传了进去。

  • 然后通过index获取interceptors集合中的拦截器最后调用intercept方法并且传入了新创建的RealInterceptorChain 。

  • 之后各个拦截器里面又调用同样的proceed方法只是index及有些参数不同,这样就完成了每个拦截器的顺序执行,这样的方式其实是运用到了责任链模式。

  • 看下具体流程图


    {`@L3@6S(HB]SY8`F9{1U25.png
  • 好了这就是整体的源码流程,下篇我们具体分析每个拦截器都来干了什么。

你可能感兴趣的:(okhttp源码解析(一) 请求流程分析)