Okhttp3 源码解析(异步同步请求)

Okhttp3 源码解析(异步同步请求)

本篇主要通过代码流程对Okhttp3的请求流程进行分析。相信okhttp3使用大家都已经掌握,这里就不再赘述。
基于okhttp3.9.1。

同步请求实例:

OkHttpClient client=new OkHttpClient();     //实例化一个OkHttpClient
        //Request request= new Request.Builder().build();
        Request request = new Request.Builder()                //实例化Request ,同时加入请求参数
                .url("https://api.github.com/repos/square/okhttp/issues")
                .header("User-Agent", "OkHttp Headers.java")
                .addHeader("Accept", "application/json; q=0.5")
                .addHeader("Accept", "application/vnd.github.v3+json")
                .build();

        Response response = null;            
        try {
            response = client.newCall(request).execute();     //获取Response 
        } catch (IOException e) {
            e.printStackTrace();
        }

OkHttpClient 所有流程的总的控制者

我们打开OkHttpClient ,查看一下官方对其的描述

Factory for {@linkplain Call calls}, which can be used to send HTTP requests and read their responses.

calls/call的工厂,它可以用来发送HTTP请求和读取他们的响应。

每一个call的创建都需要实例化OkHttpClient,同时OkHttpClient对请求的流程进行总的控制。

Request request = new Request.Builder()

这里是request 的请求集合,其中封装了我们请求的各种信息。

response = client.newCall(request).execute();

关键代码response = client.newCall(request).execute();
我们一步一步来分析,这里进行了一个同步的请求,execute()将会直接返回一个response 信息。
上面说过了client是总的流程的控制者,这里通过client创建了一个newCall

newCall

newCall又是什么?
打开代码看一下。

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

在client中通过newCall(Request request)创建了一个call对象,其通过
RealCall.newRealCall(this, request, false /* for web socket */);进行创建,所以这个流程又到了RealCall中

RealCall 请求的实际调用者

static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);   //返回一个RealCall
    call.eventListener = client.eventListenerFactory().create(call);  //????
    return call;
  }

可以看到newRealCall是一个静态方法,仅限于包内访问,所以我们不能够直接调用newRealCall(),可以看到这里通过调用自身的构造函数返回了一个RealCall对象,因为RealCall对象实现了Call接口,所以可以进行转换。

call.eventListener = client.eventListenerFactory().create(call);

接着这段代码就让人摸不着头脑了,既然已经返回了RealCall了,这个函数又是什么意思。
观看代码,发现这个eventListener 还是通过client进行调用的,不然怎么会是流程总的控制者嘛。
来到eventListenerFactory()这个工厂中来看一下。

public EventListener.Factory eventListenerFactory() {
    return eventListenerFactory;
  }

直接返回了一个eventListenerFactory,???这个eventListenerFactory我们又没有初始化过,怎么实现的?
搜索eventListenerFactory ,发现在Builder中有如下的代码。

 public Builder() {
      ...
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      ...
    }

EventListener

EventListener.NONE??什么鬼,传入一个空的类干什么。
点开EventListener

 Listener for metrics events. Extend this class to monitor the quantity, size, and duration of your application's HTTP calls.

看一下官方对其的描述,一个事件的监听器,扩展这个类以监视应用程序的HTTP调用的数量、大小和持续时间。

瞬间释然了,原来就是一个没有定义的空类,我们可以根据具体的场合对事件进行监听,通过继承这个类实现其中的方法。

好了现在client也初始化了,realcall也拿到了,requst也封装了,那接下来干嘛,进行同步请求呀

response = client.newCall(request).execute();

execute()方法,实际也就是RealCall中的execute()方法,上面已经对其进行了描述。
那就愉快的来到了execute()方法中。

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

execute()

同样的,一步一步的分析。

synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }

executed是一个boolean变量,当进行executed请求后,会将其置为true,所以一个RealCall只能够发起一次executed()请求。

captureCallStackTrace();

看到这个函数先从语义对其进行分析,捕获call的异常栈。

private void captureCallStackTrace() {
    Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
  }

retryAndFollowUpInterceptor是一个负责定位失败和重定向的Interceptor,这里通过Platform平台得到”response.body().close()”的异常栈,关于Interceptor下面会进行介绍。

eventListener.callStart(this);

eventListener?感觉好像似曾相识,对的就是我们上面的那个空的类,通过继承这个类可以实现请求事件的监听,这里因为默认的是none,所以并不会有什么效果。

client.dispatcher().executed(this);

client,果然什么都离不开你,clirent.dispatcher(),这里又到了 dispatcher类的介绍。
dispatcher会在okHttpCilent中的builder初始化,也就是一个OkhttpClient会持有一个dispatcher,dispacher通过表面意思就是分发者的意思。这里通过分发者执行同步executed()方法。

Dispatcher

Policy on when async requests are executed.

官方对其的描述是执行异步管理的策略,也就是一个异步请求的执行类。

其中有如下变量。

 /** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();   //异步请求就绪的队列

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */   
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();     //异步请求正在执行的队列

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();         //同步请求的队列 

executed()方法

接着上面看一下他的executed方法。

synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);     //将call加入同步请求队列
  }
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);   
    }

既然执行到了executed()方法,那么接下来就是得到Response 的方法,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));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

上面的方法其实就是通过各种的拦截器,通过传入的originalRequest,依次迭代进行处理,这里用到了责任链的处理模式,同时也将整个代码解耦,类似RecycleView的处理,每个模块仅仅关注于自己的部分。

在配置 OkHttpClient 时设置的 interceptors,也就是自定义的interceptors。
负责失败重试以及重定向的 RetryAndFollowUpInterceptor。
负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应的BridgeInterceptor。
负责读取缓存直接返回、更新缓存的 CacheInterceptor。
负责和服务器建立连接的 ConnectInterceptor。
配置 OkHttpClient 时设置的 networkInterceptors。
负责向服务器发送请求数据、从服务器读取响应数据的 CallServerInterceptor。

最后会发现调用了chain.proceed(originalRequest);每一个拦截器的proceed()方法中都会不断的调用这个方法,从而达到遍历所有的拦截器的作用

最后finaly中会有如下的方法
client.dispatcher().finished(this); 这个是整个请求的收尾阶段,代码如下

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!");
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

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

可以发现这是一个泛型函数,通过传入的calls的deque,因为已经完成了这个操作,所以直接将call移除掉,
这里又出现了一个新的接口Runnable idleCallback;
这又是什么东西,来到类里面看一下。

public synchronized void setIdleCallback(@Nullable Runnable idleCallback) {
    this.idleCallback = idleCallback;
  }

仅仅有一个函数用于传入这个接口,idleCallback同样的是一个提供的空接口,用于在当前没有任务执行的时候调用的方法。上面的runningCallsCount = runningCallsCount();用来判断是否还有任务在进行,当当前同步任务执行完了的时候,会调用这个接口中的函数,用来进行一些收尾的处理。

同步请求大致就这样,接下来看一下异步请求

异步请求

OkHttpClient client=new OkHttpClient();
        //Request request= new Request.Builder().build();
        Request request = new Request.Builder()
                .url("https://api.github.com/repos/square/okhttp/issues")
                .header("User-Agent", "OkHttp Headers.java")
                .addHeader("Accept", "application/json; q=0.5")
                .addHeader("Accept", "application/vnd.github.v3+json")
                .build();
        client.newCall(request).enqueue(new Callback() {   //进行异步请求
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

同样的进行一个异步请求,由于不能直接返回结果,所以需要对其传入一个call接口,用于接受是否完成或者失败。
同样的,我们直接来到RealCall中的enqueue方法中。

@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));  //直接入队

同样的还是通过client的dispatcher进行请求的分发。
来到dispatcher的enqueue方法。

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

dispatcher中维护了一个executorService线程池,上面也说到了,同时有异步请求的runningAsyncCalls()和readyAsyncCalls(),首先需要对线程池中的数量进行判断,如果当前的正在运行的线程比最大的请求数小,同时每个主机最大请求数大于这个时候主机请求的数目 说明当前主机还可以进行请求,直接将call加入正在进行的队列中,通过executorService().execute(call)执行call中的方法。 如果目前没有空闲的位置,所以必须等待,所以将其加入readyAsyncCalls中,等待下一次的调用。

猜你喜欢

转载自blog.csdn.net/zxc641483573/article/details/79140131