OKHTTP源码解析

一、OKHTTP 使用
  • 1、GET 请求
  OkHttpClient client = new OkHttpClient();

  Request request = new Request.Builder()
      .url(url)
      .build();

  Response response = client.newCall(request).execute();
  return response.body().string();

  • 2、POST请求
 public static final MediaType JSON
    = MediaType.parse("application/json; charset=utf-8");

  OkHttpClient client = new OkHttpClient();

  RequestBody body = RequestBody.create(JSON, json);

  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();

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

  return response.body().string();

二、OKHTTP源码流程分析
(一)、OKHTTP同步请求
  OkHttpClient client = new OkHttpClient(); 
  Request request = new Request.Builder()
      .url(url)
      .build(); 
  Response response = client.newCall(request).execute();

可以看出先new了一个OKHttpClient对象

1、OKHttpClient 类
  1. 里面包含了很多对象,OKHttp的很多功能模块都包装进这个类,让这个类单独提供对外的API,采用了外观模式;
  2. 而内部模块比较多,就使用了Builder模式(建造者模式);
  3. 它的方法只有一个,newCall 返回一个Call 对象 (一个准备好可以执行或取消的请求)。

创建OKHttpClient后又new 了一个Request 对象。说到Request 就不得不提 Response。

2、Request、Response类

1、Request 、Response 分别抽象成请求和响应
2、其中Request 包括Headers 和 RequestBody ,而 RequestBody 是 abstract 的,它的子类有FormBody(表单提交的) 和 MultipartBody (文件上传),分别对应了两种不同的MIME类型 FormBody :“application/x-www-form-urlencoded”
MultipartBody:“multipart/”+xxx.
3、其中Response 包括 Headers 和 ResponseBody,而 ResponseBody 也是abstract 的,所以他的子类也有两个 RealResponseBody 和 CacheResponseBody,分别代表真实响应和缓存响应。
4、由于RFC协议规定,所以所有的头部信息不是随便写的,request 的 header 与 response 的 header 的标准是不同的。OKHttp 的封装类Request 和 Response 为了应用程序的编程方便,会把一些常用的 contentLength 、code 、message 、cacheControl 、tag … 他们都是以 name - value 键值对的形式,存到网络请求的头部信息中。

根据上面的GET请求,用Builder 构建Request 对象,然后执行了 OKHttpClient类的 newCall 方法,那么就看下newCall 里面做了什么

 /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

先来看下Call 这个类

3、Call 类

Call : HTTP 请求任务的封装
可以说我们用到的操作基本上都定义在这个里面了,所以也可以说这个类是OKHttp类的核心类。我们可以通过Call对象来操作请求了,而Call 接口内部提供了Factory 工厂模式(将对象的创建延迟到工厂类的子类去进行,从而实现动态的配置)

public interface Call extends Cloneable {
  /** Returns the original request that initiated this call. */
  Request request();

  /**
   * Invokes the request immediately, and blocks until the response can be processed or is in
   * error.
   *
   * <p>To avoid leaking resources callers should close the {@link Response} which in turn will
   * close the underlying {@link ResponseBody}.
   *
   * <pre>@{code
   *
   *   // ensure the response (and underlying response body) is closed
   *   try (Response response = client.newCall(request).execute()) {
   *     ...
   *   }
   *
   * }</pre>
   *
   * <p>The caller may read the response body with the response's {@link Response#body} method. To
   * avoid leaking resources callers must {@linkplain ResponseBody close the response body} or the
   * Response.
   *
   * <p>Note that transport-layer success (receiving a HTTP response code, headers and body) does
   * not necessarily indicate application-layer success: {@code response} may still indicate an
   * unhappy HTTP response code like 404 or 500.
   *
   * @throws IOException if the request could not be executed due to cancellation, a connectivity
   * problem or timeout. Because networks can fail during an exchange, it is possible that the
   * remote server accepted the request before the failure.
   * @throws IllegalStateException when the call has already been executed.
   */
  Response execute() throws IOException;

  /**
   * Schedules the request to be executed at some point in the future.
   *
   * <p>The {@link OkHttpClient#dispatcher dispatcher} defines when the request will run: usually
   * immediately unless there are several other requests currently being executed.
   *
   * <p>This client will later call back {@code responseCallback} with either an HTTP response or a
   * failure exception.
   *
   * @throws IllegalStateException when the call has already been executed.
   */
  void enqueue(Callback responseCallback);

  /** Cancels the request, if possible. Requests that are already complete cannot be canceled. */
  void cancel();

  /**
   * Returns true if this call has been either {@linkplain #execute() executed} or {@linkplain
   * #enqueue(Callback) enqueued}. It is an error to execute a call more than once.
   */
  boolean isExecuted();

  boolean isCanceled();

  /**
   * Create a new, identical call to this one which can be enqueued or executed even if this call
   * has already been.
   */
  Call clone();

  interface Factory {
    Call newCall(Request request);
  }
}

源码中,OKHttpClient 实现了 Call.Factory 接口,返回一个RealCall 对象,那么就来看下RealCall 这个类

4、RealCall 类

1、OKhttpClient 的newCall 方法返回一个 RealCall 对象,但是需要传入一个OkHttpClient 对象 和 request 对象 (第三个参数false 表示不是 webSokcet。因此RealCall 包装了Request 对象。所以RealCall 可以很方便的使用这两个对象。
2、RealCall 里面两个关键的方法是:excute 和 enqueue 。分别用于同步和异步的执行请求。
3、RealCall 还有一个重要的方法是:getResponseWithInterceptorChain,添加拦截器,通过拦截器可以将一个流式工作分解为可配置的分段流程,即增加了灵活性也实现了解耦,关键是可以自由配置。

所以client.newCall( request ).execute();实际上执行的是RealCall 的 excute 方法,现在再来看下RealCall的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);
    }
  }

分析下这段代码

(1)、首先判断call 是否被执行过,可以看出每个Call 对象只能使用一次的原则。
synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
(2)、然后调用了 captureCallStackTrace();

  private void captureCallStackTrace() {
    Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
  }
(2.1)、captureCallStackTrace()又调用了Platform.get().getStackTraceForCloseable()
public class Platform {
  public static Platform get() {
    return PLATFORM;
  }
  /**
   * Returns an object that holds a stack trace created at the moment this method is executed. This
   * should be used specifically for {@link java.io.Closeable} objects and in conjunction with
   * {@link #logCloseableLeak(String, Object)}.
   */
  public Object getStackTraceForCloseable(String closer) {
    if (logger.isLoggable(Level.FINE)) {
      return new Throwable(closer); // These are expensive to allocate.
    }
    return null;
  }
}
(2.2)、然后调用 retryAndFollowUpInterceptor.setCallStackTrace()
public final class RetryAndFollowUpInterceptor implements Interceptor {

  public void setCallStackTrace(Object callStackTrace) {
    this.callStackTrace = callStackTrace;
  }
}

可以卡出这个方法什么都没做,就是set 了一个object 进去;

综上所示,captureCallStachTrace()这个方法其实是捕获了这个请求的Stacktrace。

(3) 、接下来到了关键部分
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);
    }

先来看下OKHttpClient的dispatcher()方法的具体内容如下

//OKHttpClient.java
  public Dispatcher dispatcher() {
    return dispatcher;
  }

由于client.dispatcher() 返回的是Dispatcher对象,那么这个 Dispatcher 对象是何时创建的?
在OKHttpClient 类里面的Build 内部类的构造函数里面

//OkHttpClient.java
public static final class Builder {
   //其它代码先忽略掉
    public Builder() {
      dispatcher = new Dispatcher();
      //其它代码先忽略掉
    }
}

所以默认执行到 Builder() 的时候就创建了一个 Dispatcher。那么再来看下dispatcher里面的 execture() 是如何处理的

  /** Used by {@code Call#execute} to signal it is in-flight. */
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

发现里面执行了runningSyncCalls.add() 方法,
在来看是怎么定义runningSyncCalls 的

//Dispatcher.java
  /** 存放了等待执行任务Call的双向队列 */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** 存放异步请求任务Call的双向任务队列 */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** 存放同步请求任务Call的双向队列 */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

可以看到 Dispatcher里面定义了三个双向队列,runningSyncCalls 是双向队列;

(4)、执行完client.dispatcher().executed(this);走到getResponseWithInterceptorChain()
  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()));
    //这个intercepor是建立客户端和服务端的连接
    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, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
	//把 chain 传递到第一个 interceptor
    return chain.proceed(originalRequest);
  }

可以看到new 了一个 ArrayList ,然后不断的 add,后面 new 了 ReallnterceptorChain 对象,最后调用了chain.proceed() 方法,先看下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()方法
由于Interceptor 是个接口,所以应该是具体的实现类 RealInterceptorChain 的 proceed 实现

  @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 , httpCode , connection 都是 null , 所以这个next对象和chain 最大的区别就是 index 属性值不同 chain 是1 ,而 next 是 1,然后取interceptor 下标为1对象的 interceptor 。由上文可知,如果开发者没有自定义Interceptor 时,首先点用 RetryAndFollowUpInterceptor,如果定义了,则调用开发者自定义的interceptor。

后面的流程是在每一个interceptor的 intercept()方法里面都会调用chain.proceed() 从而调用下一个interceptor(next) 方法,这样就遍历了 getResponseWithinterceptorChain 里面 interceptors的 item

  //RetryAndFollowUpInterceptor.java
public Response intercept(Chain chain) throws IOException {
 //忽略部分代码
 response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
 //忽略部分代码
}
//BridgeInterceptor.java
public Response intercept(Chain chain) throws IOException {
  //忽略部分代码
  Response networkResponse = chain.proceed(requestBuilder.build());
  //忽略部分代码
}
//CacheInterceptor.java
public Response intercept(Chain chain) throws IOException {
   //忽略部分代码
   networkResponse = chain.proceed(networkRequest);
   //忽略部分代码
}
//ConnectInterceptor.java
public Response intercept(Chain chain) throws IOException {
     //忽略部分代码
     return realChain.proceed(request, streamAllocation, httpCodec, connection);
}

通过源码可以知道 getResponseWithInterceptorChain 里面interceptors 的最后一个item 是 callServerInterceptor.java,最后一个Interceptor 直接返回了 response 而不进行继续递归,CallServerInterceptor 返回 response 后返回给上一个 interceptor ,一般是开发者自定义的networkInterceptor,然后开发者自定义的networkInterceptor 把他的 response 返回给上一个interceptor,以此类推。直到返回到第一个interceptor,这时候有回到 RealCall 里面的 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);
    }
  }

最后把ersponse 返回给 get 请求的返回值;到此整体的GET 请求大体流程就已经结束了。
在这里插入图片描述

(二)、OKHTTP 异步请求
OkHttpClient client = new OkHttpClient();

String run(String url) throws IOException {
  Request request = new Request.Builder()
      .url(url)
      .build();

  Response response = client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {
        }
    });
前面同样new 了 OKHttpClient 和 Request,就不说了,来看一下不一样的地方,后面异步任务进入 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));
  }

这里的 excuted 是一个标志,标志这个请求是否已经正在请求,由于 executed 默认为 false , 所以先进判断,为 true 则直接抛异常,为 false则设为 true;
接下来和同步一样先调用 captureCallStackTrace(),然后调用 client.dispatcher().enqueue( new AsycCall( responseCallback ));
client.dispatcher() 返回一个Dispatcher对象所以实际调用的是 Dispatcher 的 enqueue(),那么来看源码

 //Dispatcher.java
  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);
    }
  }

如果正在执行的异步请求小于 64 ,并且请求同一个主机小于 5 的时候就把这个 call 添加到正在运行的异步队列里面,然后用线程池去执行这个 call,否则就把 call 放到等待队列里面。
执行 call 这个call 的时候,就会走到 这个 call 的 run 方法,那么来看下 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 {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

上面看到NamedRunnable的构造方法设置了name 的 run 方法,里面设定了当前线程的name ,而NamedRunable 的方法里面又调用了 自己的抽象方法 execute ;
由此可见,NamedRunnable 的作用就是设置了线程的name ,然后回调子类的 execute 方法,那么我们来看 AsyncCall 的 execute 方法,又回到之前同步的 getResponseWithIntetceptorChain()里面,根据返回的 response 来 callback 回调。
所以OKHTTP 的大体流程如下:
在这里插入图片描述

三、OKHTTP 主要核心类

在这里插入图片描述
整体流程图
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值