网络请求框架:Okhttp:Call对象实现请求源码解析【四】

OKHttp3--调用对象RealCall源码解析【四】_没有鱼了的博客-CSDN博客

一:概述,当我们封装好 Request后需要执行这个请求,但是 OkHttp并不是直接执行 Request ,而是将 Request又封装了一层 Call对象,一个Call对象代表一个已经准备好的请求(Request), Call可以取消,同时一个 Call对象代表了一个 请求/响应 (request/response)流 。

二:Call只是一个请求接口,具体的实现是 RealCall ,不管是同步请求还是异步请求,请求的对象均是RealCall . 当我们执行同步请求时会调用它的execute方法,执行异步请求会调用enqueue方法

三:RealCall源码

        RealCall的代码并不复杂,也没有做过多的操作,而且同步异步的请求在RealCall中的操作基本差不多,只不过同步请求是在当前线程执行,而异步请求是封装了一个子线程AsyncCall去执行请求;而关于具体的网络请求过程都在拦截器里进行

/**
 * 一个Call封装一对Request和Response,能且仅能被执行一次。并且Call可以被取消。
 */
final class RealCall implements Call {
  //OKHttp客户端
  final OkHttpClient client;
  //重试和重定向拦截器
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
  //RealCall状态监听器
  final EventListener eventListener;

  //请求对象
  final Request originalRequest;
  final boolean forWebSocket;

  // RealCall是否执行过
  private boolean executed;

  RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();

    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);

    this.eventListener = eventListenerFactory.create(this);
  }

  /** 返回初始化此Call的原始请求 */
  @Override 
  public Request request() {
    return originalRequest;
  }

  /** 进行同步请求
  * 立即发出请求,一直阻塞当前线程,直到返回结果或者报错
  * 可以使用Response.body获取结果
  * 为了复用连接,需要调用Response.close关闭响应体
  */
  @Override 
  public Response execute() throws IOException {
    synchronized (this) {
      //同一个RealCall,只能执行一次
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //打印堆栈信息
    captureCallStackTrace();
    try {
      //加入分发器中的正在执行的同步请求队列
      client.dispatcher().executed(this);
      //获取请求结果
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      //通知分发器请求完成,从队列移除
      client.dispatcher().finished(this);
    }
  }

  private void captureCallStackTrace() {
    Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
  }
  
  /**
  * 进行异步请求
  * 至于何时执行这个请求由分发器决定
  * 通常是立即执行,除非当前有任务在执行或不符合限制条件
  * 如果不能立即执行,会被保存到等待执行的异步请求队列
  * 请求结束后,会通过回调接口将结果返回
  */
  @Override 
  public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    //实例化一个线程AsyncCall交给分发器,由分发器中的线程池执行这个线程
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

  //取消这个RealCall 如果请求已经有返回了,那么就不能被取消了
  @Override 
  public void cancel() {
    retryAndFollowUpInterceptor.cancel();
  }

  //判断是否执行过
  @Override 
  public synchronized boolean isExecuted() {
    return executed;
  }

  //判断是否取消了
  @Override 
  public boolean isCanceled() {
    return retryAndFollowUpInterceptor.isCanceled();
  }

  //复制一个相同的RealCall
  @SuppressWarnings("CloneDoesntCallSuperClone")
  @Override public RealCall clone() {
    return new RealCall(client, originalRequest, forWebSocket);
  }

  //StreamAllocation协调Connections,Streams,Calls三者之间的关系
  StreamAllocation streamAllocation() {
    return retryAndFollowUpInterceptor.streamAllocation();
  }

  //异步请求线程
  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() {
      //保证onFailure只被回调一次
      boolean signalledCallback = false;
      try {
        //通过拦截器获取返回结果
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          //如果请求被取消,回调onFailure
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          // 正常情况,调用onResponse
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        // 如果上面回调过,这里就不再进行回调,保证onFailure只会被调用一次
        if (signalledCallback) {
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        //通知分发器请求结束,从队列中移除该请求
        client.dispatcher().finished(this);
      }
    }
  }

  /**
   * Returns a string that describes this call. Doesn't include a full URL as that might contain
   * sensitive information.
   */
  String toLoggableString() {
    return (isCanceled() ? "canceled " : "")
        + (forWebSocket ? "web socket" : "call")
        + " to " + redactedUrl();
  }

  //返回包含此URL的字符串,无用户名,密码,查询信息
  String redactedUrl() {
    return originalRequest.url().redact();
  }
  
  //依次执行拦截器链中的拦截器获取结果
  Response getResponseWithInterceptorChain() throws IOException {
    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());
    }
    //添加连接服务器拦截器,主要负责将我们的Http请求写进网络的IO流中
    interceptors.add(new CallServerInterceptor(forWebSocket));

    //构建拦截器链依次执行每一个拦截器
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }
}

五:异步请求

      异步请求会走到内部的enqueue方法

  @Override 
  public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();

    // 实例化 AsyncCall对象
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

      首先它是RealCall的内部类,我们都知道异步请求是在子线程执行的,但是到这里我们还没有看出来子线程的影子,那我们就需要看下RealCall的父类了

  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实现了Runnable接口,从这里可以看出AsyncCall确实是在子线程执行网络请求 

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

六:同步请求

        同步请求会走到内部的execute方法

       第一步:首先出现一个同步代码块,对当前对象加锁,通过一个标志位executed判断该对象的execute方法是否已经执行过,如果执行过就抛出异常;这也就是同一个Call只能执行一次的原因
      第二步:这个是用来捕获okhttp的请求堆栈信息,不是重点
      第三步:调用Dispatcher的executed方法,将请求放入分发器,这是非常重要的一步
      第四步:通过拦截器连获取返回结果Response
     第五步:调用dispatcher的finished方法,回收同步请求

  @Override 
  public Response execute() throws IOException {
    //第一步
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //第二步
    captureCallStackTrace();
    try {
    //第三步
      client.dispatcher().executed(this);
      //第四步
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
    //第五步
      client.dispatcher().finished(this);
    }
  }

第三步和第五步都在分发器内部处理,我们重点看下 第四步

       这里实例化一个List,用来存放Interceptor对象,主要是OKHttp提供的5种拦截器

接下来实例化了一个拦截器链对象,在这个拦截器链里依次执行每个拦截器

  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);
    return chain.proceed(originalRequest);
  }

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值