欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

02.OkHttp重要类说明

程序员文章站 2022-07-13 10:58:54
...

目录介绍

  • 01.有哪些重要的类
  • 02.OKHttpClient类
  • 03.Request和Response类
  • 04.Call接口类说明
  • 05.RealCall类说明
  • 06.Dispatcher类说明
  • 07.主要流程图

01.有哪些重要的类

  • OKHttpClient类
  • Request类和Response类
  • Call类和RealCall类
  • Dispatcher类

02.OKHttpClient类说明

  • 1、里面包含了很多对象,其实OKhttp的很多功能模块都包装进这个类,让这个类单独提供对外的API,这种外观模式的设计十分的优雅。外观模式。
  • 2、而内部模块比较多,就使用了Builder模式(建造器模式)。Builder模式(建造器模式)
  • 3、它的方法只有一个:newCall.返回一个Call对象(一个准备好了的可以执行和取消的请求)。

03.Request和Response类

  • Request类说明
    • Request抽象成请求数据
    • Request包括Headers和RequestBody,而RequestBody是abstract的,他的子类是有FormBody(表单提交的)和MultipartBody(文件上传),分别对应了两种不同的MIME类型
    FormBody :"application/x-www-form-urlencoded"
    MultipartBody:"multipart/"+xxx.
    
  • Response类说明
    • Response抽象成响应数据
    • Response包括Headers和RequestBody,而ResponseBody是abstract的,所以他的子类也是有两个:RealResponseBody和CacheResponseBody,分别代表真实响应和缓存响应。
  • 关于Headers说明,头部信息不是随便写的
    • OKHttp的封装类Request和Response为了应用程序编程方便,会把一些常用的Header信息专门提取出来,作为局部变量。比如contentType,contentLength,code,message,cacheControl,tag…它们其实都是以name-value对的形势,存储在网络请求的头部信息中。

04.Call接口类说明

  • Get或者Post请求,显示用builder构建了Request对象,然后执行了OKHttpClient.java的newCall方法,那么咱们就看看这个newCall里面都做什么操作?
    //准备将来某个时候执行的{@code请求}。
    @Override 
    public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
    }
    
  • Call类详解
    • 有道词典翻译该类注释:调用是准备执行的请求。call可以取消。由于此对象表示单个请求/响应对(流),因此不能执行两次。
  • 主要是HTTP请求任务封装
    • 可以说我们能用到的操纵基本上都定义在这个接口里面了,所以也可以说这个类是OKHttp类的核心类了。我们可以通过Call对象来操作请求,同步请求execute,异步请求enqueue,这两个想必都是很熟悉呢。而Call接口内部提供了Factory工厂方法模式(将对象的创建延迟到工厂类的子类去进行,从而实现动态配置)。
    • Call接口提供了内部接口Factory(用于将对象的创建延迟到该工厂类的子类中进行,从而实现动态的配置)。
  • Call类接口
    • 继承Cloneable类,表明是可以clone的。接口中几个方法用的都非常多……
    public interface Call extends Cloneable {
    
      Request request();
      
      Response execute() throws IOException;
    
      void enqueue(Callback responseCallback);
    
      void cancel();
    
      boolean isExecuted();
    
      boolean isCanceled();
    
      Call clone();
    
      interface Factory {
        Call newCall(Request request);
      }
    }
    

05.RealCall类说明

5.1 RealCall构造

  • RealCall类构造创建对象
    • 在源码中,OKHttpClient实现了Call.Factory接口,返回了一个RealCall对象。那我们就来看下RealCall这个类。代码如下所示:
    @Override 
    public Call newCall(Request request) {
        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.eventListener = client.eventListenerFactory().create(call);
        return call;
    }
    
    • 1、OkHttpClient的newCall方法里面new了RealCall的对象,但是RealCall的构造函数需要传入一个OKHttpClient对象和Request对象(PS:第三个参数false表示不是webSokcet)。因此RealCall包装了Request对象。所以RealCall可以很方便地使用这两个对象。
    • 2、RealCall里面的两个关键方法是:execute 和 enqueue。分别用于同步和异步得执行网络请求。
    • 3、RealCall还有一个重要方法是:getResponseWithInterceptorChain,添加拦截器,通过拦截器可以将一个流式工作分解为可配置的分段流程,既增加了灵活性也实现了解耦,关键还可以自有配置,非常完美。

5.2 execute方法调用

  • client.newCall(request).execute();实际上执行的是RealCall的execute方法,现在咱们再回来看下RealCall的execute的具体实现
    • 首先是判断call是否执行过,可以看出每个Call对象只能使用一次原则。
    @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);
        }
    }
    
  • 然后接着看captureCallStackTrace方法
    • RealCall的captureCallStackTrace() 又调用了Platform.get().getStackTraceForCloseable()。
    • 其实是调用AndroidPlatform. getStackTraceForCloseable(String closer)方法。这里就不详细说了,后面详细说。
    • 然后retryAndFollowUpInterceptor.setCallStackTrace(),在这个方法里面什么都没做就是set一个object进去。
    • 综上所示captureCallStackTrace()这个方法其实是捕获了这个请求的StackTrace。
    private void captureCallStackTrace() {
        Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
        retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
    }
    
    public Object getStackTraceForCloseable(String closer) {
        if (logger.isLoggable(Level.FINE)) {
          return new Throwable(closer); // These are expensive to allocate.
        }
        return null;
    }
    

5.3 enqueue异步方法

  • client.newCall(request).enqueue();实际上执行的是RealCall的enqueue方法,现在咱们再回来看下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));
    }
    
  • 由于executed默认为false,所以先进行判断是否为true,为true则直接跑异常,没有则设置为true,可以看出executed这个是一个标志,标志这个请求是否已经正在请求中,合同步一样先调用了captureCallStackTrace();然后调用 client.dispatcher().enqueue(new AsyncCall(responseCallback));client.dispatcher()返回的是Dispatcher对象所以实际调用的是Dispatcher的enqueue()

06.Dispatcher类说明

6.1 execute同步方法源码分析

  • 然后看一下关键性代码,如下所示。
    • 进入了第一个核心类—Dispatcher的的execute方法。
    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 {
        //最后需要调用finished方法结束
      client.dispatcher().finished(this);
    }
    
  • 看下OKHttpClient的dispatcher()方法的具体内容
    • 发现client.dispatcher()返回的是Dispatcher对象,那么这个Dispatcher对象是何时创建的呢?
    public Dispatcher dispatcher() {
        return dispatcher;
    }
    
  • 在OkHttpClient.java里面Build类里面的构造函数里面
    • 默认执行Builder()放到时候就创建了一个Dispatcher
    //OkHttpClient.java
    public static final class Builder {
        public Builder() {
          dispatcher = new Dispatcher();
        }
    }
    
  • 接着看看Dispatcher类中executed执行方法
    • 里面发现是runningSyncCalls执行了add方法,可以发现runningSyncCalls是ArrayDeque对象。
    synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
    }
    
  • 查看dispatcher里面怎么定义runningSyncCalls的
    • 原来runningSyncCalls是双向队列啊,突然发现Dispatcher里面定义了三个双向队列,看**释,我们大概能明白readyAsyncCalls 是一个存放了等待执行任务Call的双向队列,runningAsyncCalls是一个存放异步请求任务Call的双向任务队列,runningSyncCalls是一个存放同步请求的双向队列。
    /** 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<>();
    
  • 接着看一下getResponseWithInterceptorChain源代码
    • 发现 new了一个ArrayList,然后就是不断的add,后面 new了 RealInterceptorChain对象,最后调用了chain.proceed()方法。
    Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        //添加开发者应用层自定义的Interceptor
        interceptors.addAll(client.interceptors());
        //这个Interceptor是处理请求失败的重试,重定向    
        interceptors.add(retryAndFollowUpInterceptor);
        //这个Interceptor工作是添加一些请求的头部或其他信息
        //并对返回的Response做一些友好的处理(有一些信息你可能并不需要)
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        //这个Interceptor的职责是判断缓存是否存在,读取缓存,更新缓存等等
        interceptors.add(new CacheInterceptor(client.internalCache()));
        //这个Interceptor的职责是建立客户端和服务器的连接
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
          //添加开发者自定义的网络层拦截器
          interceptors.addAll(client.networkInterceptors());
        }
        interceptors.add(new CallServerInterceptor(forWebSocket));
        //一个包裹这request的chain
        Interceptor.Chain chain = new RealInterceptorChain(
            interceptors, null, null, null, 0, originalRequest);
        //把chain传递到第一个Interceptor手中
        return chain.proceed(originalRequest);
    }
    
    • 看下RealInterceptorChain的构造函数。可以发现这里面仅仅只是一些赋值操作。
    public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
          HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
          EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
        this.interceptors = interceptors;
        this.connection = connection;
        this.streamAllocation = streamAllocation;
        this.httpCodec = httpCodec;
        this.index = index;
        this.request = request;
        this.call = call;
        this.eventListener = eventListener;
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
        this.writeTimeout = writeTimeout;
    }
    
    • 跟踪下chain.proceed()方法,看看做了什么。
    public interface Interceptor {
      Response intercept(Chain chain) throws IOException;
    
      interface Chain {
        Request request();
    
        Response proceed(Request request) throws IOException;
    
        @Nullable Connection connection();
    
        Call call();
      }
    }
    
    • 由于Interceptor是个接口,所以应该是具体实现类RealInterceptorChain的proceed实现。
    public final class RealInterceptorChain implements Interceptor.Chain {
    
      @Override public Response proceed(Request request) throws IOException {
        return proceed(request, streamAllocation, httpCodec, connection);
      }
    
      public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
          RealConnection connection) throws IOException {
        if (index >= interceptors.size()) throw new AssertionError();
    
        calls++;
    
        // If we already have a stream, confirm that the incoming request will use it.
        if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must retain the same host and port");
        }
    
        // If we already have a stream, confirm that this is the only call to chain.proceed().
        if (this.httpCodec != null && calls > 1) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must call proceed() exactly once");
        }
    
        // Call the next interceptor in the chain.
        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);
    
        // Confirm that the next interceptor made its required call to chain.proceed().
        if (httpCodec != 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;
      }
    }
    
    • 看到在proceed方面里面又new了一个RealInterceptorChain类的next对象,温馨提示下,里面的streamAllocation, httpCodec, connection都是null,所以这个next对象和chain最大的区别就是index属性值不同chain是0.而next是1,然后取interceptors下标为1的对象的interceptor。由从上文可知,如果没有开发者自定义的Interceptor时,首先调用的RetryAndFollowUpInterceptor,如果有开发者自己定义的interceptor则调用开发者interceptor。

6.2 enqueue异步方法

  • 先看call类中的代码
    • client.dispatcher()返回的是Dispatcher对象所以实际调用的是Dispatcher的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().enqueue方法操作了什么
    • 根据源码和注释大家可以看到如果正在执行的异步请求小于64,并且请求同一个主机小于5的时候就先往正在运行的队列里面添加这个call,然后用线程池去执行这个call,否则就把他放到等待队列里面。执行这个call的时候,自然会去走到这个call的run方法。
    private int maxRequests = 64;
    private int maxRequestsPerHost = 5;
    
    synchronized void enqueue(AsyncCall call) {
      //如果正在执行的请求小于设定值即64,并且请求同一个主机的request小于设定值即5
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
          //添加到执行队列,开始执行请求
          runningAsyncCalls.add(call);
          //获得当前线程池,没有则创建一个
          executorService().execute(call);
        } else {
          //添加到等待队列中
          readyAsyncCalls.add(call);
        }
    }
    
  • 那么咱们看下AsyncCall.java这个类,而AsyncCall.java又继承自NamedRunnable.java咱们就一起看下他们的源码
    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();
        } finally {
          Thread.currentThread().setName(oldName);
        }
      }
    
      protected abstract void execute();
    }
    
    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 {
              responseCallback.onFailure(RealCall.this, e);
            }
          } finally {
            client.dispatcher().finished(this);
          }
        }
    }
    
    • 上面看到NamedRunnable的构造方法设置了name在的run方法里面设定为当前线程的name,而NamedRunnable的run方法里面调用了它自己的抽象方法execute,由此可见NamedRunnable的作用就是设置了线程的name,然后回调子类的execute方法,那么我们来看下AsyncCall的execute方法。貌似好像又回到了之前同步的getResponseWithInterceptorChain()里面,根据返回的response来这只callback回调。

07.主要流程图

  • 根据上面分析,大概流程图如下所示
    • 02.OkHttp重要类说明
相关标签: OkHttp