Android基于Okhttp 3.5对Okhttp源码解析一

为什么不用最新版本 4.9呢?因为kotlin版本的不太好看。

基于Okhttp 3.5版本解析

Exec Code:
同步:

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().build();
Call call = client.newCall(request);
call.execute();

异步:

enquene code:
OkhttpClient client = new OkHttpClient()
Request request = new Request.Builder().build();
Call call = client.newCall(request);
call.enquene();

Analyse:

  1. 两种构造器:
    第一种New Okhttpclient();
    这种会设置根据默认的Builder进行设置,主要包含dispatcher调度器,protocolsHttp协议版本,connectionspec包括针对TLS和普通Http的连接,eventListenerFactory这是Call的状态监听器,Connectionpool连接池,hostnamevertify主机验证等。
    实际上调用的是this(new Builder());
    第二种New OkhttpClient().newBuilder().……build();这种就设置了上面的一些参数。
final Dispatcher dispatcher;
final Proxy proxy;
final List<Protocol> protocols;
final List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors;
final List<Interceptor> networkInterceptors;
final ProxySelector proxySelector;
final CookieJar cookieJar;
final Cache cache;
final InternalCache internalCache;
final SocketFactory socketFactory;
final SSLSocketFactory sslSocketFactory;
final CertificateChainCleaner certificateChainCleaner;
final HostnameVerifier hostnameVerifier;
final CertificatePinner certificatePinner;
final Authenticator proxyAuthenticator;
final Authenticator authenticator;
final ConnectionPool connectionPool;
final Dns dns;
final boolean followSslRedirects;
final boolean followRedirects;
final boolean retryOnConnectionFailure;
final int connectTimeout;
final int readTimeout;
final int writeTimeout;
final int pingInterval;

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

OkHttpClient(Builder builder) {
  this.dispatcher = builder.dispatcher;
  this.proxy = builder.proxy;
  this.protocols = builder.protocols;
  this.connectionSpecs = builder.connectionSpecs;
  this.interceptors = Util.immutableList(builder.interceptors);
  this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
  this.proxySelector = builder.proxySelector;
  this.cookieJar = builder.cookieJar;
  this.cache = builder.cache;
  this.internalCache = builder.internalCache;
  this.socketFactory = builder.socketFactory;

  boolean isTLS = false;
  for (ConnectionSpec spec : connectionSpecs) {
    isTLS = isTLS || spec.isTls();
  }

  if (builder.sslSocketFactory != null || !isTLS) {
    this.sslSocketFactory = builder.sslSocketFactory;
    this.certificateChainCleaner = builder.certificateChainCleaner;
  } else {
    X509TrustManager trustManager = systemDefaultTrustManager();
    this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
    this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
  }

  this.hostnameVerifier = builder.hostnameVerifier;
  this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
      certificateChainCleaner);
  this.proxyAuthenticator = builder.proxyAuthenticator;
  this.authenticator = builder.authenticator;
  this.connectionPool = builder.connectionPool;
  this.dns = builder.dns;
  this.followSslRedirects = builder.followSslRedirects;
  this.followRedirects = builder.followRedirects;
  this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
  this.connectTimeout = builder.connectTimeout;
  this.readTimeout = builder.readTimeout;
  this.writeTimeout = builder.writeTimeout;
  this.pingInterval = builder.pingInterval;
}

最后执行的build():

public OkHttpClient build() {
  return new OkHttpClient(this);
}
  1. Request的分析
    New Request.Builder():
    2.1:Request为final类,无法被继承,不能被覆盖,执行速度比一般类更快。
    2.2:Buidler()的时候设置了默认的请求方式和请求头,默认的请求方式为GET,请求头也是final类,builder模式,内部维护着一个初始大小为20的ArrayList。
    这是Requeust类(截取部分):
public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final RequestBody body;
  final Object tag;

这是request的Builder

public Builder() {
  this.method = "GET";
  this.headers = new Headers.Builder();
}

这是Header的Builder

public static final class Builder {
  final List<String> namesAndValues = new ArrayList<>(20);

2.3 build()方法
可见,request构建的时候必须要设置url,否则会抛出异常,然后把参数设置自身并返回。

public Request build() {
  if (url == null) throw new IllegalStateException("url == null");
  return new Request(this);
}
  1. Call
    3.1 看看client.newCall,就是Okhttp的newCall,返回的是RealCall
@Override public Call newCall(Request request) {
  return new RealCall(this, request, false /* for web socket */);
}

3.2 RealCall的构造函数

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

上面可以看出Okhttp支持websocket但是默认是false不支持,那如需websocket该怎样使用呢,简单说一下
第一步:继承Okhttp的抽象类websocketListener,重写onfail ,onclose,onOpen等方法
第二步:构建OkHttpClient和Request对象
第三部:调用newWebSocket建立连接
第四部:调用shutdown关闭

EchoWebSocketListener listener = new EchoWebSocketListener();
    Request request = new Request.Builder()
            .url("ws://echo.websocket.org")
            .build();
    OkHttpClient client = new OkHttpClient();
    client.newWebSocket(request, listener);
 
client.dispatcher().executorService().shutdown();

构造函数设置了okhttpclient对象和请求信息request的封装以及是否支持websocket,然后构建了一个Retryandfollowupinterceptor
3.3 Retryandfollowupinterceptor

public RetryAndFollowUpInterceptor(OkHttpClient client, boolean forWebSocket) {
  this.client = client;
  this.forWebSocket = forWebSocket;
}

里面只是将okhttpclient和是否支持websocket传了进去。
3.4然后执行同步或者异步请求
4.分析同步请求
实际上是调用realcall的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);
  }
}

4.1 先用同步锁锁住当前类,realcall内部维护者一个私有的boolean executed对象,执行过抛出异常若没有接着往下走,并且将该变量置为true。
4.2调用captureCallStackTrace():打印错误信息
4.3 client.dispatcher().executed(this)
4.3.1 client.dispatcher:其实是在 new okhttpClient的时候设置的dispatcher分发器
4.3.2 execute方法:注意是关键字同步锁方法

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

runningSyncCalls其实是一个队列
private final Deque runningSyncCalls = new ArrayDeque<>();
Deque是一个能够快速访问任何一个元素和高效删除插入的一个双向队列。
将需要执行的同步call添加进来。
如果空闲的话立即执行。
4.3.3 然后执行getresponsewithIntercepterchain方法

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

4.3.4 先看interceptor 这是一个接口

public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    Connection connection();
  }
}

4.3.5 集合首先添加okhttpclient里自定义的intercepter,然后
添加realcall构造函数生成的retryandfollowupinterceptor,然后bridgeinterceptor,cacheinterceptor,connectInterceptor,如果不是websocket则添加networkinterceptor,接着CallserverIntercaptor,然后构造RealInterceptorChain,将添加了所有interceptor的集合参数传了进去,再返回chain.proceed。
4.3.6 注意到interceptors只是一个添加拦截器的集合,真正的处理在RealInterceptorChain的proceed方法,先看下RealinterceptorChanin的构造方法

public final class RealInterceptorChain implements Interceptor.Chain {
  private final List<Interceptor> interceptors;
  private final StreamAllocation streamAllocation;
  private final HttpCodec httpCodec;
  private final Connection connection;
  private final int index;
  private final Request request;
  private int calls;

  public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
      HttpCodec httpCodec, Connection connection, int index, Request request) {
    this.interceptors = interceptors;
    this.connection = connection;
    this.streamAllocation = streamAllocation;
    this.httpCodec = httpCodec;
    this.index = index;
    this.request = request;
  }

和Call类似,Call是一个接口,RealCall是一个实现类,Chain也是一个接口,Realinterceptor就是其实现类。同样的Interceptor也是一个接口。

public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    Connection connection();
  }
}

chain即为链子,将包含所有拦截器的集合里的拦截器依次取出链式执行。构造方法里主要知道interceptors和request即可。
4.3.7 然后看最终的proceed方法

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

这里proceed调用的是由构造函数传过来的几个参数,再看真正的执行

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
    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.httpCodec != 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.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);
  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");
  }

  return response;
}

第一行我们看到如果index > interceptors.size()即抛出AssertionError,断言错误异常。然后继续构建RealInterceptorChain对象传入必要的参数,让实现了Interceptor接口的各个拦截器去执行对于的intercept方法,最终得到response对象。具体的我们下节分析。。

猜你喜欢

转载自blog.csdn.net/kururunga/article/details/111949943