Android干货面试题网络

OkHttp原理解析1(框架流程篇)

2020-02-03  本文已影响0人  酱爆大头菜
OkHttp3.png
一直想写一篇 简洁而不失内涵 的OKHTTP源码分析,甚至从19年春节前就开始翻阅OkHttp的源码。但是赶上春节事多心杂,没能将心中所想梳理出来。
现在疫情当前,节约了外出活动的时间,静心打磨了此文,希望对看本文的小伙伴有所帮助,更希望 武汉坚强,祖国安康

本文源码基于OkHttp3.14.6,该版本是Java版最新的一版,后续的4.*全面使用了Kotlin,如有需要可再进行分析。

针对OkHttp我打算开两篇进行分析。

第1篇分析整体的框架设计,以及大方向的请求流程。
第2篇分析具体拦截器的功能逻辑。

好,我们开始表演。

在翻看源码之前,对OkHttp的了解只停留在使用层面,对Api使用非常的6。完全没关心过内部原理。更别提设计思想了。
有句 德玛西亚 名言咋说来着 新手拼的是英雄,技能,熟练度。高玩靠的是走位,意识,英雄池。
这句话你品,你细品~~~

本文争取以一个高玩的姿态去解读OkHttp的源码,至于有多高呢?
嗯~~~ 还是这么高。。。


image.png

我们再看源码的时候有一个技巧,不一定非要挨个类去逐行阅读,枯燥无味不说,关键是很难和功能相对应,可根据使用方式切入,根据逻辑调用链,层层跟进。
本文呢又是一篇深入浅出的题材,还是那迷人的姿势,还是那熟悉的套路。
从使用到原理,从架构到逻辑。
使用体现的是框架的能力,架构承载的是框架的灵魂。
我们将从以下几个问题出发,循循渐进,层层深入。


1. OkHttp有什么优势?为啥要分析的是OkHttp而不是其他框架?

其实Android的网络框架有很多,比如Android-Async-Http,Volley,OkHttp,Retrofit,那为啥偏要分析OkHttp呢?因为它屌啊~~~
我们先看一个这个对比图就明白了。

对比分析 Android-Async-Http volley OkHttp Retrofit
技术分析 基于HttpClient 基于HttpUrlConnection 基于Socket, 和HttpUrlConnection同级但并不属于HttpUrlConnection 基于Okhttp
优势 自动智能请求重试 ;持久化cookie存储 1.支持图片加载;网络请求的排序。
2.优先级处理缓存。
3.多级别取消请求。
4.生命周期控制,退出后自动取消请求。
5.可拓展性好;可支持HttpClient、HttpUrlConnection、和OkHttp
1.高性能Http请求库。
2.支持SPDY,共享同一个Socket来处理同一个服务器所有的请求.
3.支持http2.0、websocket;支持同步、异步。
4.内部封装了线程池、数据转换、参数使用、错误处理等。
5.支持GZIP来减少数据流量。
6.基于NIO和OKio,性能更高。
1.Api牛逼
2.支持通过注解配置参数,url等信息。
3.支持Gson,Jackson,Protobuf。
4.支持RxJava。
5.代码简化;解耦彻底。
劣势 Android5.0之后不推荐用HttpClient ,并且该框架通知维护。 Volley的Request和Response都是把数据放到byte数组里,不支持输入输出流,把数据放到数组中,如果文件多了,数组就会大,消耗内存 ... ...

目前相对主流的框架Retrofit,Glide中都是内置了OkHttp,而Retrift自己即是网络框架,且它都基于OkHttp,可见OkHttp是怎样一个地位。

2. OkHttp的使用方式有哪些?

接下来将秀8种操作,看好了您嘞。


/**
  * 1.同步Get请求
  * 2.异步Get请求
  * 3.同步Post请求
  * 4.异步Post请求
  * 5.Post提交文件
  * 6.Post提交from表单
  * 7.文件字符串复合提交
  * 8.拦截器使用
  */

  OkHttpClient okHttpClient = new OkHttpClient();

    /**
     * 同步Get请求
     */
    private void SyncGet() {
        try {
            Request request = new Request.Builder()
                    .url("url")
                    .build();
            Call call = okHttpClient.newCall(request);
            Response response = call.execute();
        } catch (Exception e) {

        }

    }

    /**
     * 异步Gost请求
     */
    private void AsyncGet() {
        Request request = new Request.Builder()
                .url("url")
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //请求失败
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //请求成功
            }
        });

    }

    /**
     * 同步Post请求
     */
    private void SyncPost() {
        try {
            MediaType JSON = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
            String str = "通信数据";
            Request request = new Request.Builder().url("url").post(RequestBody.create(JSON, str)).build();
            Call call = okHttpClient.newCall(request);
            Response response = call.execute();
        } catch (Exception e) {

        }

    }

    /**
     * 异步Post请求
     */
    private void AsyncPost() {
        MediaType JSON = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
        String str = "通信数据";
        Request request = new Request.Builder().url("url").post(RequestBody.create(JSON, str)).build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //请求失败
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //请求成功
            }
        });
    }

    private void postFile() {
        MediaType fileMediaType = MediaType.parse("text/x-markdown; charset=utf-8");
        Request request = new Request.Builder()
                .url("url")
                .post(RequestBody.create(fileMediaType, new File("sd/mnt/a.png")))
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //请求失败
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //请求成功
            }
        });
    }

    /**
     * Post提交from表单
     */
    private void postFrom() {
        MediaType fileMediaType = MediaType.parse("text/x-markdown; charset=utf-8");
        Request request = new Request.Builder()
                .url("url")
                .post(new FormBody.Builder().add("key", "value").build())
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //请求失败
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //请求成功
            }
        });
    }

  /**
     * Post提交组合数据(字符串+文件)
     */
    private void postMultipartBody() {
        MediaType fileMediaType = MediaType.parse("image/png");
        RequestBody requestBody = RequestBody.create(fileMediaType, new File("sd/mnt/1.png"));
        MultipartBody multipartBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"title\""),
                        RequestBody.create(null, "文字")//这样可以直接添加数据,无需单独创建RequestBody
                )
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"image\""),
                        RequestBody.create(fileMediaType, new File("sd/mnt/1.png"))//这样可以直接添加文件,无需单独创建RequestBody
                )
                .addFormDataPart("key", "value")//添加表单数据
                .addFormDataPart("file", "fileName", requestBody)
                .build();
        Request request = new Request.Builder()
                .url("url")
                .post(multipartBody)
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //请求失败
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //请求成功
            }
        });
    }


    /**
     * 使用拦截器
     */
    private void postAndInterceptor() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new MyInterceptor())
                .build();
        MediaType fileMediaType = MediaType.parse("image/png");
        RequestBody requestBody = RequestBody.create(fileMediaType, new File("sd/mnt/1.png"));
        MultipartBody multipartBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("key", "value")//添加表单数据
                .addFormDataPart("file", "fileName", requestBody)
                .build();
        Request request = new Request.Builder()
                .url("url")
                .post(multipartBody)
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //请求失败
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //请求成功
            }
        });
    }

    /**
     * 拦截器
     */
    public class MyInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            Log.d("TAG", "请求返回数据为:" + response.body().string());

            return null;
        }
    }
3. OkHttp的架构是什么样的?

这个问题挺深入,唯有此图以示天下。

整体架构图.png

上图主要以执行流程来划分,其主要涉及的类包含以下几个

4. OkHttp的内部是咋实现的?

又到了你么最喜欢的讲道理摆姿势的环节了。
分析OkHttp的内部实现可以从使用角度出发,以使用逻辑分析框架入口,然后层层跟进。我们以普通的get请求为例,主要涉及以下几个入口。

我们逐个分析一下。
4.1. OkHttpClient okHttpClient = new OkHttpClient();内部执行了哪些逻辑?我们看下源码

//OkHttpClient的构造函数
public OkHttpClient() {
    this(new Builder());
  }
//OkHttpClient的构造函数
  OkHttpClient(Builder builder) {
    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;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      X509TrustManager trustManager = Util.platformTrustManager();
      this.sslSocketFactory = newSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    if (sslSocketFactory != null) {
      Platform.get().configureSslSocketFactory(sslSocketFactory);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.callTimeout = builder.callTimeout;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;

    if (interceptors.contains(null)) {
      throw new IllegalStateException("Null interceptor: " + interceptors);
    }
    if (networkInterceptors.contains(null)) {
      throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
    }
  }
    //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;
    }
  //OkHttpClient 中静态内部类Builder的构造方法
    Builder(OkHttpClient okHttpClient) {
      this.dispatcher = okHttpClient.dispatcher;
      this.proxy = okHttpClient.proxy;
      this.protocols = okHttpClient.protocols;
      this.connectionSpecs = okHttpClient.connectionSpecs;
      this.interceptors.addAll(okHttpClient.interceptors);
      this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
      this.eventListenerFactory = okHttpClient.eventListenerFactory;
      this.proxySelector = okHttpClient.proxySelector;
      this.cookieJar = okHttpClient.cookieJar;
      this.internalCache = okHttpClient.internalCache;
      this.cache = okHttpClient.cache;
      this.socketFactory = okHttpClient.socketFactory;
      this.sslSocketFactory = okHttpClient.sslSocketFactory;
      this.certificateChainCleaner = okHttpClient.certificateChainCleaner;
      this.hostnameVerifier = okHttpClient.hostnameVerifier;
      this.certificatePinner = okHttpClient.certificatePinner;
      this.proxyAuthenticator = okHttpClient.proxyAuthenticator;
      this.authenticator = okHttpClient.authenticator;
      this.connectionPool = okHttpClient.connectionPool;
      this.dns = okHttpClient.dns;
      this.followSslRedirects = okHttpClient.followSslRedirects;
      this.followRedirects = okHttpClient.followRedirects;
      this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure;
      this.callTimeout = okHttpClient.callTimeout;
      this.connectTimeout = okHttpClient.connectTimeout;
      this.readTimeout = okHttpClient.readTimeout;
      this.writeTimeout = okHttpClient.writeTimeout;
      this.pingInterval = okHttpClient.pingInterval;
    }
//通过静态内部类Builder的build()方法可创建 OkHttpClient 对象。
 public OkHttpClient build() {
      return new OkHttpClient(this);
    }

我们分析下这一大段代码,其实逻辑内容非常简单,主要干了这么几件事。

4.2. Request request = new Request.Builder().url("url").build();内部又干了啥?
从写法上看,Request 一样也使用了构建者模式,我们分开Request.Builder(),url("url"),build()一个一个看。

//Request构造函数
Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tags = Util.immutableMap(builder.tags);
  }
//Request的静态内部类Builder构造函数
 public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }
  //Request的静态内部类Builder构造函数
    Builder(Request request) {
      this.url = request.url;
      this.method = request.method;
      this.body = request.body;
      this.tags = request.tags.isEmpty()
          ? Collections.emptyMap()
          : new LinkedHashMap<>(request.tags);
      this.headers = request.headers.newBuilder();
    }
  //Request的静态内部类Builder设置url方法
    public Builder url(HttpUrl url) {
      if (url == null) throw new NullPointerException("url == null");
      this.url = url;
      return this;
    }

    /**
     *  Request的静态内部类Builder设置url方法
     *
     * @如果url是无效的则抛出 throws IllegalArgumentException  通过调用HttpUrl.get(url)避免这种异常,
     * 无效的url返回null
     */
    public Builder url(String url) {
      if (url == null) throw new NullPointerException("url == null");

      // Silently replace web socket URLs with HTTP URLs.
      if (url.regionMatches(true, 0, "ws:", 0, 3)) {
        url = "http:" + url.substring(3);
      } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
        url = "https:" + url.substring(4);
      }

      return url(HttpUrl.get(url));
    }

    /**
     * Request的静态内部类Builder设置url方法
     *
     * @throws IllegalArgumentException if the scheme of {@code url} is not {@code http} or {@code
     * https}.
     */
    public Builder url(URL url) {
      if (url == null) throw new NullPointerException("url == null");
      return url(HttpUrl.get(url.toString()));
    }

    // Request的静态内部类Builder设置build方法
    public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }

我们总结下 new Request.Builder().url("url").build()干了几件事。

4.3. Call call = okHttpClient.newCall(request);又是干什么的呢?
以上的4.1 , 4.2均是为了创建okHttpClient,Request对象,以及初始化一数据,并没有进行其他操作。
okHttpClient.newCall(request);又做了什么操作呢?

 /**
   * okHttpClient的newCall()
   * 准备request,将在某个时间执行。 
   */
  @Override public Call newCall(Request request) {
     //最后这个参数是否为web socket默认传false
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
 /**
   *RealCall.newRealCall(...)
   *实例化RealCall对象,初始化RealCall.transmitter。
   */
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;
  }
 /**
   *RealCall(...)
   */
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
  }
 /**
   *Transmitter类构造函数 。
   */
public Transmitter(OkHttpClient client, Call call) {
    this.client = client;
    this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
    this.call = call;
    this.eventListener = client.eventListenerFactory().create(call);
    this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
  }

总结:这一堆居然还是在创建对象,真正的请求还没有开始。

4.4. call.enqueue(new Callback() {... });应该开始请求了吧...
前边准备的所有准备均为了最后这一步请求,我们看下逻辑是怎么操作的。

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.callStart();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
//transmitter.callStart();
public void callStart() {
    this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    eventListener.callStart(call);
  }

这块有点复杂我们一点一点的分析,最后进行总结。
首先call.enqueue()中进行了执行状态赋值,防止重复执行请求。
其次调用了transmitter.callStart();启动堆栈的跟踪,以及eventListener的一些回调处理。
最后即是最关键的异步 client.dispatcher().enqueue(new AsyncCall(responseCallback));是真正的请求流程。
我继续深入分析

//Dispatcher.enqueue()
void enqueue(AsyncCall call) {
    synchronized (this) {
      //readyAsyncCalls是一个准备调用的AsyncCall队列
      readyAsyncCalls.add(call);

      // 如果不是WebSocket,将通过call.host查找是否有运行中的AsyncCall ,如果有将通过AtomicInteger类型共享到当前 AsyncCall 对象中。
      if (!call.get().forWebSocket) {
        AsyncCall existingCall = findExistingCallWithHost(call.host());
        //异步请求,OkHttp会对有相同主机的call在请求时进行记数,通过AtomicInteger对象进行即时同步。
        //这个计数对后续的请求有影响,我们后边再详细分析。
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
      }
    }
    //真正执行操作
    promoteAndExecute();
  }
//循环runningAsyncCalls和readyAsyncCalls队列
  @Nullable private AsyncCall findExistingCallWithHost(String host) {
    for (AsyncCall existingCall : runningAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    for (AsyncCall existingCall : readyAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    return null;
  }
/**
   *readyAsyncCalls中满足条件的对象移动到runningAsyncCalls中 并且在 executor service上运行。 
   * 必须同步调用,因为要回调用户的代码
   *
   * 如果调度程序当前正在运行,则返回true
   */
  private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));

    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      //循环readyAsyncCalls队列。
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();
        //如果运行队列runningAsyncCalls超过了maxRequests直接break。(默认值为64)
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        //如果当前的主机计数器>5则continue,这个计数器就是上述enqueue()方法的计数器。
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
        从readyAsyncCalls中移除
        i.remove();
        //相同主机的asyncCall计数器+1
        asyncCall.callsPerHost().incrementAndGet();
        executableCalls.add(asyncCall);
        //添加到runningAsyncCalls队列中
        runningAsyncCalls.add(asyncCall);
      }
      //运行状态赋值,异步/同步只要有一个在运行则为true。
      isRunning = runningCallsCount() > 0;
    }

    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
     //开始运行,具体的运行逻辑我们后续分析。
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }

ok,我们总结下Dispatcher.enqueue()干了什么事

asyncCall.executeOn(executorService());中又干了啥?

//Dispatcher.executorService()
//如果executorService 为null则创建一个ThreadPoolExecutor线程池
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;
  }

/**
    * AsyncCall.executeOn()
     * 尝试通过 executorService启动执行AsyncCall
     * 如果 executor已经关闭了则尝试清楚,并报失败
     */
    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        //线程池执行AsyncCall
        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        transmitter.noMoreExchanges(ioException);
        //回调onFailure
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
          //如果没成功,调用OkHttpClient.dispatcher().finished(this);
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }

/**
  * Dispatcher.finished()
  *失败
  */
  void finished(AsyncCall call) {
    //AsyncCall 中相同主机计数器-1。
    call.callsPerHost().decrementAndGet();
    finished(runningAsyncCalls, call);
  }
//Dispatcher.finished(...)
private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      //从runningAsyncCalls中移除call。
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }
    //重新调用promoteAndExecute()
    boolean isRunning = promoteAndExecute();

    if (!isRunning && idleCallback != null) {
      //如果同步异步均没有运行了并且idleCallback 不为空 则通知当前为空闲状态了。
      idleCallback.run();
    }
  }

我们再总结下asyncCall.executeOn(executorService())到底干了啥。

executorService.execute(this);是执行请求的逻辑内容,我们详细看下
executorService是一个线程池,而this代表的是AsyncCall这个类,现在其实可以发现AsyncCall实际上继承的是NamedRunnable,而NamedRunnable实现了Runnable,这下就简单了,我们直接找Runnable的run方法即可。

public abstract class NamedRunnable implements Runnable {
...
  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      //主要执行了这个方法,这个方法实际是一个抽象方法,需要看实现类的实现。
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }
  protected abstract void execute();
}

//AsyncCall.execute()
@Override 
protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
        Response response = getResponseWithInterceptorChain();
        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 {
          responseCallback.onFailure(RealCall.this, e);
        }
      } catch (Throwable t) {
        cancel();
        if (!signalledCallback) {
          IOException canceledException = new IOException("canceled due to " + t);
          canceledException.addSuppressed(t);
          responseCallback.onFailure(RealCall.this, canceledException);
        }
        throw t;
      } finally {
        //移除当前AsyncCall
        client.dispatcher().finished(this);
      }
    }

我们观察以上代码大部分是异常处理的逻辑,而try中第一句即返回了Response对象,因此,我们主要看getResponseWithInterceptorChain()中的逻辑。

  Response getResponseWithInterceptorChain() throws IOException {
    // 建立一个完整的拦截器堆栈
    List<Interceptor> interceptors = new ArrayList<>();
     //将创建okhttpclient时的拦截器添加到interceptors
    interceptors.addAll(client.interceptors());
    //重试拦截器,负责处理失败后的重试与重定向
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    //请求转化拦截器(用户请求转为服务器请求,服务器响应转为用户响应)
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //缓存拦截器。负责
    //1.根据条件,缓存配置,有效期等返回缓存响应,也可增加到缓存。
    //2.设置请求头(If-None-Match、If-Modified-Since等) 服务器可能返回304(未修改)
    //3.可配置自定义的缓存拦截器。
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //网络连接拦截器,主要负责和服务器建立连接。
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      //创建okhttpclient时设置的networkInterceptors
      interceptors.addAll(client.networkInterceptors());
    }
    //数据流拦截器,主要负责像服务器发送和读取数据,请求报文封装和解析。
    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);
      }
    }
  }

其实上述逻辑中,主要干了3件事。

我们只要搞懂创建责任链的逻辑,以及启动责任链的逻辑就全都明白了,ok,我们看下具体代码

//通过RealInterceptorChain构造函数创建每一个责任对象
 public RealInterceptorChain(List<Interceptor> interceptors, Transmitter transmitter,
      @Nullable Exchange exchange, int index, Request request, Call call,
      int connectTimeout, int readTimeout, int writeTimeout) {
    this.interceptors = interceptors;
    this.transmitter = transmitter;
    this.exchange = exchange;
    this.index = index;
    this.request = request;
    this.call = call;
    this.connectTimeout = connectTimeout;
    this.readTimeout = readTimeout;
    this.writeTimeout = writeTimeout;
  }
//启动责任链代码
 @Override 
 public Response proceed(Request request) throws IOException {
    return proceed(request, transmitter, exchange);
  }
//启动责任链代码
  public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
      throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // 如果我们已经有一个流,请确认传入的请求将使用它。
    if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // 如果我们已经有一个流,确认这是对链的唯一调用。
    if (this.exchange != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // 调用链中的下一个拦截器,注意参数index+1,通过+1的方式循环interceptors list中的拦截器
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    //执行当前拦截器逻辑,并设置下一个拦截器对象。
    Response response = interceptor.intercept(next);

    // 确认下一个拦截器对chain.proceed()进行了所需的调用。
    if (exchange != 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;
  }

虽然看着上述这段代码很长,但是大篇幅都在判断各种异常情况,实际做的事非常简单。
1.创建完RealInterceptorChain后,通过procee()判断各种异常,并获取当前Interceptor对象。
2.通过Interceptor.intercept(RealInterceptorChain)启动当前拦截器逻辑,并且触发下一个拦截器启动。
3.如果当前拦截器出现异常等错误,则终止责任链。

具体的情况我们还需要看一个拦截器内部的逻辑,我们以简单的ConnectInterceptor为例。

public final class ConnectInterceptor implements Interceptor {
  public final OkHttpClient client;

  public ConnectInterceptor(OkHttpClient client) {
    this.client = client;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    //chain实际上是下一个责任对象。
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    Transmitter transmitter = realChain.transmitter();

    // 我们需要网络来满足这个要求。可能用于验证条件GET。
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);
    //执行下一个拦截器责任对象的proceed方法。
    return realChain.proceed(request, transmitter, exchange);
  }
}

可见,Interceptor.intercept(Chain chain)接收的是下一个拦截器责任对象。
该方法中执行了自己拦截器该有的逻辑,如果没异常则直接通过下一个拦截器责任对象的proceed()启动了下一个拦截器逻辑。
ok我们在回头看下,AsyncCall.execute()中的finally中的那句代码 client.dispatcher().finished(this);

//Dispatcher.finished()
 void finished(AsyncCall call) {
    call.callsPerHost().decrementAndGet();
    finished(runningAsyncCalls, call);
  }

  private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      //移除队列,如果失败则抛异常
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }
    //这个方法是不是有点眼熟,主要用来将readyAsyncCalls符合条件的添加到runningAsyncCalls中,并运行。
    boolean isRunning = promoteAndExecute();
     //闲置调用
    if (!isRunning && idleCallback != null) {
      idleCallback.run();
    }
  }

ok至此所有的流程都非常清楚了。至于请求细节需要具体到了每一个拦截器里。我打算单独开一篇来分析。
看到此处,如果对你有一点帮助,麻烦给个赞鼓励一下。

其实写博客是一个自驱的学习管理方式。能给小伙伴说明白的,那你必定早已心中有数。翻阅伟大的框架代码就好比面对面跟这个伟人学习。

上一篇下一篇

猜你喜欢

热点阅读