OkHttp源码分析系列--整体的工作流程

OkHttp作为时下最受欢迎的网络请求框架之一,它有着自己的优点:

  • 使用了众多的设计模式(如:Builder模式、责任链模式等),尤其是在Interceptor中使用的责任链模式,将整个网络请求串联起来最为经典。
  • 基于Http请求头、DiskLruCache等缓存策略实现Respose的缓存。
  • 内部维护了队列线程池,可以轻松实现并发任务。
  • 拥有自动维护的socket连接池,减少握手次数。

除了上面的优点,其实还有很多,这里就不一一详述了。

大家都应该知道OkHttp执行网络请求有两种方式:

  • 1、同步网络请求--Call.execute();
  • 2.异步网络请求--Call.enqueue(Callback responseCallback)。

那么接下来就从这两个方面进行分析。

1.Call对象的真实面貌——RealCall

  • OkHttpClient#newCall():

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

    从上述代码,我们发现Call的实现类原来是RealCall,并且创建RealCall对象时,会需要OkHttpClient、Request以及forWebSocket。

  • RealCall详细分析:

OkHttp源码分析系列--整体的工作流程_第1张图片
RealCall.png
  • RealCall构造方法
    构造方法中除了会保存之前的OkHttpClient、Request、boolean forWebSocket之外,还会创建RetryAndFollowUpIntercptor对象,这个对象主要作用是在网络请求是出现异常情况进行重新连接的,具体的分析放在后面。

  • execute()同步请求方法:
    既然是同步网络请求,那么就意味着不需要为它去执行分配线程的操作了。并且它应该会直接进入网络请求的操作。

          @Override public Response execute() throws IOException {
                ...
                // 通过Dispatcher管理网络请求——对于同步请求只是将其添加到runningSyncCalls队列中。
                client.dispatcher().executed(this);
                // 构建一堆的网络请求拦截器
                Response result = getResponseWithInterceptorChain();
                return result;
                ...
            }
    
  • getResponseWithInterceptorChain() 分析:

          Response getResponseWithInterceptorChain() throws IOException {
              // Build a full stack of interceptors.
              // 1.创建interceptors集合。
              List interceptors = new ArrayList<>();
              // 2.添加用户设置的所有的interceptors。
              interceptors.addAll(client.interceptors());
              // 3.添加错误重连的Interceptor,此对象在构造方法中被创建。
              interceptors.add(retryAndFollowUpInterceptor);
              // 4.添加BridgeInterceptor拦截器,将用户设置的Request进行高度封装(请求头、关于响应体的解gzip)。
              interceptors.add(new BridgeInterceptor(client.cookieJar()));
              // 5.添加处理网络请求对应缓存的拦截器
              interceptors.add(new CacheInterceptor(client.internalCache()));
              // 6.添加进行Socket连接的拦截器
              interceptors.add(new ConnectInterceptor(client));
              // 7.添加用户定义的网络拦截器
              if (!forWebSocket) {
                interceptors.addAll(client.networkInterceptors());
              }
              // 8.添加Socket下与服务器进行数据读写操作的拦截器。
              interceptors.add(new CallServerInterceptor(forWebSocket));
          
              // 9.责任链模式中保存了下一拦截器的链条对象(递归执行的关键)。
              Interceptor.Chain chain = new RealInterceptorChain(
                  interceptors, null, null, null, 0, originalRequest);
              return chain.proceed(originalRequest);
          }
    

    构建一堆的Interceptor之后,执行RealInterceptorChain中的proceed()方法,开启整个网络请求责任链工作。

    RealInterceptorChain # proceed()源码分析:

          public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
                RealConnection connection) throws IOException {
              ...
              // Call the next interceptor in the chain.
              // 1.创建保存了下一个interceptor的链条对象。
              RealInterceptorChain next = new RealInterceptorChain(
                  interceptors, streamAllocation, httpCodec, connection, index + 1, request);
              // 2.执行当前当前interceptor的intercept()方法。
              Interceptor interceptor = interceptors.get(index);
              Response response = interceptor.intercept(next);
              ...
              return response;
            }
    
  • 再来分析enqueue()异步网络请求:

    既然是异步网络请求,那么肯定需要两个条件:
    1、网络请求的任务体;
    2、执行具体任务的工作线程。

          @Override 
          public void enqueue(Callback responseCallback) {
              ...
              client.dispatcher().enqueue(new AsyncCall(responseCallback));
              ...
          }
    
  • AsyncCall.execute()源码分析:

          protected void execute() {
            ...
            // 我们发现其实AsyncCall最后也是做了这件事情
            Response response = getResponseWithInterceptorChain();
            ...  
          }
    

2.管理网络请求任务的策略器——Dispatcher

Dispatcher主要的工作就是给异步网络请求任务(AsyncCall)分配工作线程并执行。


OkHttp源码分析系列--整体的工作流程_第2张图片
Dispatcher.png
  • Dispatcher.enqueue()源码分析:

      synchronized void enqueue(AsyncCall call) {
          // 1.检测正在执行的异步网络请求数是否小于maxRequests
          // &&相同主机的异步网络请求数是否小于maxRequestsPerHost
          if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
            // 2.满足条件,添加到runningAsyncCalls队列并且执行。
            runningAsyncCalls.add(call);
            executorService().execute(call);
          } else {
            // 3.不满足条件,添加到readyAsyncCalls。
            readyAsyncCalls.add(call);
          }
       }
    
  • Dispatcher.executed()源码分析:

      synchronized void executed(RealCall call) {
          // 直接添加到runningSyncCalls队列
          runningSyncCalls.add(call);
       }
    

关于Okhttp的整体工作流程,基本上就是这个样子。至于Interceptor的源码分析,会在后续的文章中给出。最后把整体流程图贴出来:

OkHttp源码分析系列--整体的工作流程_第3张图片
OkHttp.png

你可能感兴趣的:(OkHttp源码分析系列--整体的工作流程)