Android OkHttp(三)源码解析

来源:互联网 发布:c语言源文件名有那些 编辑:程序博客网 时间:2024/05/16 09:37

    前面两篇文章,我们介绍了OKHttp的基本用法,今天这篇文章将从OkHttp源码的角度来分析OkHttp的整个工作流程。

初始化一个OkHttpClient对象,

    OkHttpClient mOkHttpClient = new OkHttpClient();

OkHttpClient的构造函数中又初始化了一个Builder对象,

   public OkHttpClient() {    this(new Builder());  }

Builder的构造函数中,默认会创建对象以及一些属性,Builder对象是用来构造网络请求的。这种设计模式和Android的对话框中的Builder几乎是一个意思。

 public Builder() {      dispatcher = new Dispatcher();      protocols = DEFAULT_PROTOCOLS;      connectionSpecs = DEFAULT_CONNECTION_SPECS;      proxySelector = ProxySelector.getDefault();      cookieJar = CookieJar.NO_COOKIES;      socketFactory = SocketFactory.getDefault();      hostnameVerifier = OkHostnameVerifier.INSTANCE;      certificatePinner = CertificatePinner.DEFAULT;      proxyAuthenticator = Authenticator.NONE;      authenticator = Authenticator.NONE;      connectionPool = new ConnectionPool();      dns = Dns.SYSTEM;      followSslRedirects = true;      followRedirects = true;      retryOnConnectionFailure = true;      connectTimeout = 10_000;      readTimeout = 10_000;      writeTimeout = 10_000;    }
接着,创建一个请求,

  Request request = new Request.Builder()        .url(url)        .build(); 
Request类是HTTP请求,它携带了请求地址、请求方法、请求头部、请求体以及其他信息。它也是通过Builder模式创建的。Request.Builder().build()源码,

    public Request build() {      if (url == null) throw new IllegalStateException("url == null");      return new Request(this);    }
Request的构造方法,

   private Request(Builder builder) {    this.url = builder.url;    this.method = builder.method;    this.headers = builder.headers.build();    this.body = builder.body;    this.tag = builder.tag != null ? builder.tag : this;  }
发起请求有两种方式,一种是同步,一种是异步,下面分别看看如何实现,

同步请求,

 Response  response = mOkHttpClient.newCall(request).execute();
Response是HTTP响应,它继承自Closeable(Closeable继承自AutoCloseable,AutoCloseable资源自动关闭的接口),它携带了请求、网络请求协议、返回状态码、请求头、响应体等等,其中,网络请求协议是Protocol,Protocol是一个枚举类型,包含4中类型,

 public enum Protocol {  /**   * An obsolete plaintext framing that does not use persistent sockets by default.   */  HTTP_1_0("http/1.0"),  /**   * A plaintext framing that includes persistent connections.   *   * <p>This version of OkHttp implements <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC   * 2616</a>, and tracks revisions to that spec.   */  HTTP_1_1("http/1.1"),  /**   * Chromium's binary-framed protocol that includes header compression, multiplexing multiple   * requests on the same socket, and server-push. HTTP/1.1 semantics are layered on SPDY/3.   *   * <p>This version of OkHttp implements SPDY 3 <a   * href="http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1">draft 3.1</a>. Future   * releases of OkHttp may use this identifier for a newer draft of the SPDY spec.   */  SPDY_3("spdy/3.1"),  /**   * The IETF's binary-framed protocol that includes header compression, multiplexing multiple   * requests on the same socket, and server-push. HTTP/1.1 semantics are layered on HTTP/2.   *   * <p>HTTP/2 requires deployments of HTTP/2 that use TLS 1.2 support {@linkplain   * CipherSuite#TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256} , present in Java 8+ and Android 5+. Servers   * that enforce this may send an exception message including the string {@code   * INADEQUATE_SECURITY}.   */  HTTP_2("h2");    }
接着看

OkHttpClient.newCall(request);

Call类是一个准备执行的请求,它可以被取消,它代表着一个单一的请求/响应流,不能被执行两次。Call类是一个抽象类,

public interface Call {  /** 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>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}.   *   * <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();  interface Factory {    Call newCall(Request request);  }}
newCall()方法是创建一个Call对象,

    @Override     public Call newCall(Request request) {    return new RealCall(this, request);  }
RealCall类继承自Call类,下面展示RealCall()方法的代码,
    protected RealCall(OkHttpClient client, Request originalRequest) {    this.client = client;    this.originalRequest = originalRequest;    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);  }

接着是RealCall的execute()方法。execute()方法是同步方法,即一直等待http请求, 直到返回了响应. 在这之间会阻塞进程, 所以通过同步方法不能在Android的主线程中执行, 否则会报错。

OKHttp提供了execute()方法(同步方法)和enqueue()方法(异步方法),下面我们先看看execute()方法(同步方法),

   @Override public Response execute() throws IOException {    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    try {      client.dispatcher().executed(this);      Response result = getResponseWithInterceptorChain();      if (result == null) throw new IOException("Canceled");      return result;    } finally {      client.dispatcher().finished(this);    }  }

execute()方法,首先判断是否已执行过,如果已经执行过,则抛出异常信息,也就是说一次Call实例只能调用一次execute()方法,和我们之前说的一样。

如果未执行,则调用Dispatcher类的executed()方法将该Call加入到一个双端队列中,

   ...   private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//双端队列   ...       /** Used by {@code Call#execute} to signal it is in-flight. */  synchronized void executed(RealCall call) {    runningSyncCalls.add(call);  }

 接着调用getResponseWithInterceptorChain()方法返回Response对象,最后finally中,调用Dispatcher的finished()方法,在从已经执行的双端队列中移除本次Call。

 void finished(RealCall call) {    finished(runningSyncCalls, call, false);  }  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();    }  }

通过上面分析,真正发出网络请求,返回结果应该是getResponseWithInterceptorChain()方法,那么接下来,主要看看这个方法

  private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {      interceptors.addAll(client.networkInterceptors());    }    interceptors.add(new CallServerInterceptor(        retryAndFollowUpInterceptor.isForWebSocket()));    Interceptor.Chain chain = new RealInterceptorChain(        interceptors, null, null, null, 0, originalRequest);    return chain.proceed(originalRequest);  }
仔细查看便会发现,该方法是组装各种拦截器为一个拦截器链,最后调用RealInterceptorChain的proceed()方法,来处理这个请求,

 @Override public Response proceed(Request request) throws IOException {    return proceed(request, streamAllocation, httpStream, connection);  }  public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,      Connection 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.httpStream != null && !sameConnection(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.httpStream != 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, httpStream, connection, index + 1, request);    Interceptor interceptor = interceptors.get(index);    Response response = interceptor.intercept(next);    // Confirm that the next interceptor made its required call to chain.proceed().    if (httpStream != 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");    }    return response;  }
拦截器Interceptor和拦截器链Chain都是接口,

public interface Interceptor {  Response intercept(Chain chain) throws IOException;  interface Chain {    Request request();    Response proceed(Request request) throws IOException;    Connection connection();  }}

下面用一张流程图来说明拦截器链递归从拦截器中返回Response(这个过程很类似Android中的事件处理机制)


下面再看看enqueue()方法(异步方法),指在另外的工作线程中执行http请求, 请求时不会阻塞当前的线程, 所以可以在Android主线程中使用。

  @Override public void enqueue(Callback responseCallback) {    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    client.dispatcher().enqueue(new AsyncCall(responseCallback));  }
该方法和同步方法一样,首先都校验这个Call是否已经被执行,如果执行过,就报异常。如果为执行,则调用Dispatcher分发器的enqueue()方法。首先,我们看看AsyncCall这个类,

 final class AsyncCall extends NamedRunnable {    private final Callback responseCallback;    private AsyncCall(Callback responseCallback) {      super("OkHttp %s", redactedUrl().toString());      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);      }    }  }
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();}
AsyncCall–实际上是一个Runnable,在run()方法中调用了execute()方法,在该方法中,我们又看到既熟悉又陌生的代码(getResponseWithInterceptorChain()),

 Response response = getResponseWithInterceptorChain();
执行该方法后,根据响应结果设置回调方法的结果。AsyncCall执行完调用Dispatcher的finished(this)方法,

 void finished(AsyncCall call) {    finished(runningAsyncCalls, call, true);  } 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();    }  }
finished()方法先从runningAsyncCalls(异步请求队列)删除已经执行的异步请求,然后接着调用了promoteCalls()方法,

 private void promoteCalls() {    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {      AsyncCall call = i.next();      if (runningCallsForHost(call) < maxRequestsPerHost) {        i.remove();        runningAsyncCalls.add(call);        executorService().execute(call);      }      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.    }  }
首先判断runningAsyncCalls(异步请求队列)是否还有请求,如果有,则返回;否则readyAsyncCalls(异步调用准备任务)是否为空,如果为空,则返回;否则,循环readyAsyncCalls(异步调用准备任务),将call加入到runningAsyncCalls(异步请求队列)中,并在readyAsyncCalls(异步调用准备任务)删除掉该call,接着线程池执行call。

下面接着看Dispatcher分发器的enqueue()方法,

 synchronized void enqueue(AsyncCall call) {    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {      runningAsyncCalls.add(call);      executorService().execute(call);    } else {      readyAsyncCalls.add(call);    }  }
如果runningAsyncCalls的大小小于最大请求数量(最大线程数量、并发数量)并且call小于最大主机请求限制,那么将call 加入到runningAsyncCalls中,接着线程池执行call;否则,将call加入到readyAsyncCalls(异步调用准备任务)。

PS: runningCallsForHost()方法,循环判断cal的hostl和runningAsyncCalls的中的call的host相同的数量。同一请求是否超过想过请求同时存在的最大值。

  private int runningCallsForHost(AsyncCall call) {    int result = 0;    for (AsyncCall c : runningAsyncCalls) {      if (c.host().equals(call.host())) result++;    }    return result;  }

可以看到请求的最核心代码,与Dispatcher类分不开,下面就看看Dispatcher类,Dispatcher是异步请求的策略,

public final class Dispatcher {  private int maxRequests = 64;  private int maxRequestsPerHost = 5;  private Runnable idleCallback;  /** Executes calls. Created lazily. */  private ExecutorService executorService;  /** 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<>();  ...}
  Dispatcher维护了如下变量,
    int maxRequests = 64: 最大并发请求数为64
    int maxRequestsPerHost = 5: 每个主机最大请求数为5
    Runnable idleCallback:Runnable对象,在删除任务时执行
    ExecutorService executorService:消费者池(也就是线程池)
    Deque<AsyncCall> readyAsyncCalls:缓存,异步调用准备执行任务
    Deque<AsyncCall> runningAsyncCalls:正在运行的异步任务,包含取消尚未完成的调用

    Deque<RealCall> runningSyncCalls: 正在运行的同步任务,包含取消尚未完成的调用

至此,OKHttp的源码分析就结束了!希望本篇文章对读者有所收获!微笑

下面结合本篇文章,总结OKHttp的整体流程,流程图如下所示,















0 0
原创粉丝点击