Okhttp细解之一

       今天来拆解一下okhttp;分析一下okhttp如何做到这么好;以及我们需要掌握什么样的技能或者思路去实现一个自己的“okhttp”;那先从入口开始看;

      1.OkHttpClient  ;先看头部信息下面备注了;


//Cloneable 浅copy ,Call.Factory实现工厂接口(针对于普通接口)WebSocket.Factory实现工厂接口(针对websocket请求的接口)
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {

}

        a、我们现在先搞明白上面实现接口的目的;第一个Cloneable这个是浅copy使用的;暂时真的没感觉OkHttpClient能在什么场合使用到;但是这个还是提供了;Call.Factory =>主要是实现RealCall这个类;这个类里面是实现普通的网络请求的方式;WebSocket.Factory =>主要实现RealWebSocket这个类;这个类里面实现webscoket的请求方式;

        b、看OkHttpClient的参数是什么;下面都进行备注了;

  static final List DEFAULT_PROTOCOLS = Util.immutableList(
      Protocol.HTTP_2, Protocol.HTTP_1_1);//创建一个只读的;不可以修改的list;设置默认的 http/2 ,http/1.1

  static final List DEFAULT_CONNECTION_SPECS = Util.immutableList(
      ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT);//创建一个只读的;不可以修改的list;TLS配置
  static {
    Internal.instance = new Internal() {//创建一些方法里面实现一些需要做的方法;后续讲
       ...
    };
  }
  final Dispatcher dispatcher;//开非核心线程进行,异步耗时操作(网络请求)
  final Proxy proxy;//默认空值
  final List protocols;//设置网络类型
  final List connectionSpecs;//设置TLS的
  final List interceptors;//拦截器,仅支持初始化设置
  final List networkInterceptors;//网络拦截器,仅支持初始化设置
  final ProxySelector proxySelector;//设置安全的认证操作
  final CookieJar cookieJar;//默认没有cookies
  final Cache cache;//缓存
  final InternalCache internalCache;//网络缓存
  final SocketFactory socketFactory;//创建一个对象并将其连接到指定远程端口上的指定远程地址
      // 对象还将绑定到提供的本地地址和端口。使用为此工厂建立的对象选项配置对象。
      //如果有安全管理器,checkConnect 则使用主机地址port 及其参数调用其方法。这可能会导致SecurityException。
  final SSLSocketFactory sslSocketFactory;//设置保护HTTPS连接的工厂
  final CertificateChainCleaner certificateChainCleaner;//设置限制哪些证书受信任的证书
  final HostnameVerifier hostnameVerifier;//注册认证的方式
  final CertificatePinner certificatePinner;//反抓包
  final Authenticator proxyAuthenticator;//返回一个请求,该请求包含满足{@code response}中的身份验证的凭据。如果无法满足条件,则返回null,默认没有
  final Authenticator authenticator;//返回一个请求,该请求包含满足{@code response}中的身份验证的凭据。如果无法满足条件,则返回null。默认没有

  final ConnectionPool connectionPool;//连接池 = 线程池 + 消息队列
  final Dns dns;//DNS配置
  final boolean followSslRedirects;//是否允许Ssl重定向,默认true
  final boolean followRedirects;//是否允许重定向,默认true
  final boolean retryOnConnectionFailure;//是否连接失败时重试,默认true
  final int connectTimeout;//连接超时时间,默认10_000(10秒)
  final int readTimeout;//读取超时时间,默认10_000(10秒)
  final int writeTimeout;//写入超时时间,默认10_000(10秒)
  final int pingInterval;//ping的时间间隔 默认 0

那么我们从OkHttpClient里面看到几个重要点:看一下能够调用的方法;发现到都是获取配置;并没有设置配置的接口;所以对应的OkHttpClient并没有直接提供对应的设置;

Okhttp细解之一_第1张图片

所以OkhttpClient初始化OkHttpClient(Builder builder) 借助于内部类Builder进行设置;

那么看一下这个内部类的builder的参数

  Dispatcher dispatcher;
    Proxy proxy;
    List protocols;//设置默认的 http/2 ,http/1.1
    List connectionSpecs;//TLS配置
//下面和上面的okhttp一样
    final List interceptors = new ArrayList<>();
    final List networkInterceptors = new ArrayList<>();
    ProxySelector proxySelector;
    CookieJar cookieJar;
    Cache cache;
    InternalCache internalCache;
    SocketFactory socketFactory;
    SSLSocketFactory sslSocketFactory;
    CertificateChainCleaner certificateChainCleaner;
    HostnameVerifier hostnameVerifier;
    CertificatePinner certificatePinner;
    Authenticator proxyAuthenticator;
    Authenticator authenticator;
    ConnectionPool connectionPool;
    Dns dns;
    boolean followSslRedirects;
    boolean followRedirects;
    boolean retryOnConnectionFailure;
    int connectTimeout;
    int readTimeout;
    int writeTimeout;
    int pingInterval;

初始化方法Builder()(这个是默认初始化的)和Builder(OkHttpClient okHttpClient)(可以将上次的okHttpClient设置的东西传递回去)

Okhttp细解之一_第2张图片

所以这个时候,先初始化一个builder类,再去重新设置该builder里面的部分方法;或者参数

那么我在builder里面挑出几个重要的点来讲吧;

2、首先Dispatcher这个类很重要;首先这个类干这几件事情:

   1、创建非核心线程池executorService -》为之后的网络请求做异步处理;

    2、设置了readyAsyncCalls队列(准备请求,开始网络请求数大于阀值64,以及不能有相同正在请求的host数量超过5个),这个其实就是缓存暂时不请求的接口;在请求完毕之后留在重新触发;

    3、设置runningAsyncCalls队列;异步请求的;

    4、设置了runningSyncCalls队列;同步请求的;

    5、所以总的在请求数是runningAsyncCalls.size()+runningSyncCalls.size();

   Okhttp细解之一_第3张图片

看一下图;里面的enqueue(AsyncCall call);添加进去做一个判断(异步操作)

(runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost)

runningAsyncCalls.add(call);//请求添加到队列

executorService().execute(call);//开始进行异步请求

如果添加在准备队列里面,当请求结束的时候;回调该方法

 private  void finished(Deque 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();//是否将ready里面的值加到run里面(异步)
      runningCallsCount = runningCallsCount();//获取请求的数量
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();//当无网络请求之后都会进行一次回调
    }
  }

这样的话,就完成了;一次网络请求;这个讲解的是异步以及是Dispatcher类;并不涉及真正的网络请求之类的;

下面在说明一下同步请求的方式:

这个就涉及到RealCall里面的execute()方法;会调用到.executed(this);然后添加进去

  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

结束的时候也会调用finish的方法;这个就不涉及到是否进行最大值多少个之类的;来了就是请求;

我们现在来看一下请求的触发点;当然我们直讲重要的点RealCall

/*
 * Copyright (C) 2014 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package okhttp3;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.internal.NamedRunnable;
import okhttp3.internal.cache.CacheInterceptor;
import okhttp3.internal.connection.ConnectInterceptor;
import okhttp3.internal.connection.StreamAllocation;
import okhttp3.internal.http.BridgeInterceptor;
import okhttp3.internal.http.CallServerInterceptor;
import okhttp3.internal.http.RealInterceptorChain;
import okhttp3.internal.http.RetryAndFollowUpInterceptor;
import okhttp3.internal.platform.Platform;

import static okhttp3.internal.platform.Platform.INFO;

final class RealCall implements Call {
  final OkHttpClient client;
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;

  /** The application's original request unadulterated by redirects or auth headers. */
  final Request originalRequest;
  final boolean forWebSocket;

  // Guarded by this.
  private boolean executed;

  RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

  @Override public Request request() {
    return originalRequest;
  }

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

  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();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));//触发异步请求;线程池
  }

  @Override public void cancel() {
    retryAndFollowUpInterceptor.cancel();
  }

  @Override public synchronized boolean isExecuted() {
    return executed;
  }

  @Override public boolean isCanceled() {
    return retryAndFollowUpInterceptor.isCanceled();
  }

  @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
  @Override public RealCall clone() {
    return new RealCall(client, originalRequest, forWebSocket);
  }

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

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

  String redactedUrl() {
    return originalRequest.url().redact();
  }

  Response getResponseWithInterceptorChain() throws IOException {//网络请求的地方,以及插入拦截器,这个位子就是实现责任链的地方
    // Build a full stack of interceptors.
    List 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、enqueue(Callback responseCallback) --异步方式

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));//触发runnable地方
  }

    final class AsyncCall extends NamedRunnable {
    ...

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

 2、 Response execute()---同步的方式

//同步方法 
@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);
    }
  }

所以重点是Response getResponseWithInterceptorChain()这个方法体;

我们现在去瞧瞧:

 Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());//先添加client提供的拦截器,build里面才能添加;这个就是我们自定义的拦截器;这个是还没有请求的拦截器
    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);//FIRST 触发
  }

其中拦截器这个类是:

//拦截器都需要实现这个类
public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;//其中proceed是触发下面一个类执行的条件

    Connection connection();
  }
}

其中我们还需要看一下RealInterceptorChain这类:

  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      Connection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

   ...

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);//设置下一个拦截器的Chain,从0开始

       ...

    return response;
  }

那么我们从FIRST开始看;触发了proceed;那么如果没有添加我们的拦截器;直接触发RetryAndFollowUpInterceptor拦截器;

public final class RetryAndFollowUpInterceptor implements Interceptor {
    ...
  @Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();

    streamAllocation = new StreamAllocation(
        client.connectionPool(), createAddress(request.url()), callStackTrace);//复用和创建连接池的操作;这个在OkhttpClient里面实现方法;

    int followUpCount = 0;
    Response priorResponse = null;
    while (true) {
    ...
        response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);//上面的代码实现;将连接池设置进去
       ...
  }

...
}

这个创建连接池之后开始proceed;那么又调用RealInterceptorChain生成下一个拦截器的chain并且调用intercept

BridgeInterceptor填充cookie等,再次调用chain.proceed(requestBuilder.build());这个不需要在传递连接池;

然后在次触发CacheInterceptor,一样的再次触发ConnectInterceptor,CallServerInterceptor,触发之后在依次执行之前的proceed之后的方法;当然这个是继续执行;最终回到RetryAndFollowUpInterceptor里面执行followUpRequest然后返回response;

然后我们进行回调等处理;这样不管是异步还是同步;走的方式都是责任链的;

之后会继续讲解一下里面实现的细节;比如如何创建scoket等等

你可能感兴趣的:(android,安卓)