02.OkHttp重要类说明

目录介绍
  • 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.主要流程图

  • 根据上面分析,大概流程图如下所示
    • image
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值