2019-05-13OkHttp 源码流程分析

先来看 OKhttp 的简单使用

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
        builder.writeTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//写操作 超时时间
        builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读操作 超时时间

        //日志拦截器
        //注意使用这个拦截器需要增加 com.squareup.okhttp3:logging-interceptor:3.4.1 配置
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        builder.addInterceptor(loggingInterceptor);

        OkHttpClient client = builder.build();
        Request request = new Request.Builder()
                .url("http://wanandroid.com/wxarticle/chapters/")
                .build();
        okhttp3.Call call = client.newCall(request);
        call.enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                Log.e("TAG", "onFailure: ---->" + e.getMessage());
            }

            @Override
            public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
                Log.e("TAG", "OKhttp onResponse: ----->" + response.body().string());
            }
        });

先来看 OkHttpClient.Builder 做了什么

    public Builder() {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();
      if (proxySelector == null) {
        proxySelector = new NullProxySelector();
      }
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      callTimeout = 0;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;
    }

初始化了一大堆东西

     //给 connectTimeout 重新赋值,返回本身,常见的Builder写法
    public Builder connectTimeout(long timeout, TimeUnit unit) {
      connectTimeout = checkDuration("timeout", timeout, unit);
      return this;
    }

    //添加拦截器,就是往 interceptors 中添加数据
    public Builder addInterceptor(Interceptor interceptor) {
      if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
      interceptors.add(interceptor);
      return this;
    }

常见的一些重新设置或添加的方法

    //直接 new OkHttpClient 并将自己传过去
    public OkHttpClient build() {
      return new OkHttpClient(this);
    }

    OkHttpClient(Builder builder) {
    //通过Builder设置的值,赋给 OkHttpClient
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
    this.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;

    //.....
  }

最后通过 build 方法创建出一个 OkHttpClient 对象,很熟悉的Builder设计模式,通过Builder来构建 Client 对象。继续往下看:

    Request request = new Request.Builder()
                .url("http://wanandroid.com/wxarticle/chapters/")
                .build();

这一段代码和 OkHttpClient.Builder 方式一样,通过 Request.Builder() 来构建 Request 对象,也是做一些保存数据检验操作。这里就不多说了,继续看:

    okhttp3.Call call = client.newCall(request);

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

    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.transmitter = new Transmitter(client, call);
    return call;
    }

通过上面可以知道, okhttp3.Call 的实际对象为 RealCall ,所以后面调用的 call.enqueue 方法就是 RealCall.enqueue 方法,来看该方法:

    
  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      //executed 默认值为false
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //通知 EventListener 调用 callStart 方法
    //应该是一个生命周期监听方法
    transmitter.callStart();
    //主要的是这一句
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

通过前面 OkHttpClient.Builder 可以知道 dispatcher() 返回的是 Dispatcher 对象

    
  void enqueue(AsyncCall call) {
    synchronized (this) {
      //准备队列中添加该 call
      //
      readyAsyncCalls.add(call);

      //RealCall.newRealCall(this, request, false /* for web socket */); 根据这个可以知道这个if会进来
      //判断当前 host 的Call 是否已经存在
      //如果存在将已经存在的 callsPerHost 赋值给当前call
      // callsPerHost 也就是主机数,后面用来判断是否超过最大主机数
      if (!call.get().forWebSocket) {
        AsyncCall existingCall = findExistingCallWithHost(call.host());
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
      }
    }
    //执行
    promoteAndExecute();
  }

往readyAsyncCalls队列中增加当前的call,最后执行,来看执行的方法

    private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));
    //新建执行的Call的list 
    List executableCalls = new ArrayList<>();
    //标志是否正在运行
    boolean isRunning;
    synchronized (this) {
      //循环 readyAsyncCalls,也就是准备队列
      for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        //得到准备队列中的Call
        AsyncCall asyncCall = i.next();
        //判断正在运行的队列中的请求数是否大于最大请求数,大于则返回
        //最大值为 64
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        //判断主机数是否大于最大主机数,大于则返回
        //最大值为5
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
        //如果没有返回,将当前数据从准备队列中移除
        i.remove();
        //将主机数加1
        asyncCall.callsPerHost().incrementAndGet();
        //往executableCalls 中增加当前call
        executableCalls.add(asyncCall);
        //运行队列中增加call
        runningAsyncCalls.add(asyncCall);
      }
       //运行队列中存在数据,说明正在运行
      isRunning = runningCallsCount() > 0;
    }
    //循环 executableCalls 
    //加入请求数和主机数都没有超出最大值,executableCalls 就会有数据,否则没有
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      //执行 executeOn 方法
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }

最后会执行到 AsyncCall 的 executeOn 方法,AsyncCall 是 RealCall 的一个内部类,在 client.dispatcher().enqueue(new AsyncCall(responseCallback)); 时创建,来看 AsyncCall.executeOn 方法

    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      //标记为,是否执行成功
      boolean success = false;
      try {
        //调用线程池 execute 方法
        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        transmitter.noMoreExchanges(ioException);
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }

其中 executorService 是在 asyncCall.executeOn(executorService()); 时候赋值的,来看executorService() 方法

  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;
  }

其实就是创建一个线程池,根据线程池可以知道 executorService.execute(this); this 是一个 实现 Runnable 接口的对象,并且调用 execute 方法后会调用 run 方法。AsyncCall 继承 NamedRunnable 去看 NamedRunnable

//实现了 Runnable 接口
public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    //为当前线程设置名称
    Thread.currentThread().setName(name);
    try {
      //调用 execute 
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

最后调用 execute 方法,execute 方法为抽象方法,又会回到AsyncCall的 execute 方法中

      @Override protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
        //调用 getResponseWithInterceptorChain 得到请求数据
        Response response = getResponseWithInterceptorChain();
        signalledCallback = true;
        // responseCallback 就是使用时调用call.enqueue(new okhttp3.Callback() )传过来的
        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 {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
         //请求结束后将队列中call移除
        client.dispatcher().finished(this);
      }
    }

最终来到 getResponseWithInterceptorChain 方法中

    
  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List interceptors = new ArrayList<>();
    //通过addInterceptor()方法添加的拦截器条件到interceptors头部
    interceptors.addAll(client.interceptors());
    //重试拦截器
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    //配置请求头拦截器,配置请求头信息
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //缓存拦截器
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //初始化socket连接
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      //通过addNetworkInterceptor()方法添加对的拦截器添加到获取数据之前
      interceptors.addAll(client.networkInterceptors());
    }
    //通过前面初始化的socket,和服务器通信
    interceptors.add(new CallServerInterceptor(forWebSocket));
    //责任链的设计模式,不断调用拦截器,直到其中一个拦截器返回数据
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
      //得到网络返回数据
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }

getResponseWithInterceptorChain 方法就是通过责任链的设计模式,不断循环拦截器直到又数据返回,如何请求网络得到数据,可以自行了解 CallServerInterceptor 的 intercept 方法。

其中责任链的设计模式:你想请一个月的假,你上报给了你的上级领导,你的上级领导批不了这么长的假;他也上报给他的上级领导,最后一层层的上报,直到上报到了老板,老板给你批了假,老板将结果反馈给上报给他的下属,这个下属又反馈个他的下属,一层层往下,最后到你自己这里,得到答复可以请假。如果不明白,可以将这些类拷贝到idea中,自己实现一遍

到这里,数据已经获取,通过 responseCallback 返回,responseCallback 就是调用时候传过来的

    //这里的 okhttp3.Callback() 就是 responseCallback 的值
    call.enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                Log.e("TAG", "onFailure: ---->" + e.getMessage());
            }

            @Override
            public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
                Log.e("TAG", "OKhttp onResponse: ----->" + response.body().string());
            }
        });

最后得到数据,因为使用了线程池,所以 onResponse 是在异步线程中的

OKhttp 主要使用了Builder模式和责任链模式,只要掌握了这两种模式,那么 OKhttp 就不是很难的东西。

你可能感兴趣的:(2019-05-13OkHttp 源码流程分析)